Compare commits
150 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b164038846 | ||
|
|
5c46960734 | ||
|
|
a7f4f0c737 | ||
|
|
b64dd501dd | ||
|
|
1679675aa1 | ||
|
|
640466f301 | ||
|
|
9c9771a371 | ||
|
|
1922b3ce65 | ||
|
|
83e819908a | ||
|
|
0924aa644b | ||
|
|
7711ce1d66 | ||
|
|
7dae63e586 | ||
|
|
1bcaa45492 | ||
|
|
66cb114f0d | ||
|
|
1c5d60dcfd | ||
|
|
b6da6356fc | ||
|
|
c09670cc45 | ||
|
|
464f5b7bed | ||
|
|
c799235c24 | ||
|
|
a2860e70a5 | ||
|
|
95a96d46a6 | ||
|
|
81f3dbda31 | ||
|
|
4eb4191843 | ||
|
|
ca433d8a61 | ||
|
|
8f4dfe1514 | ||
|
|
ee42f5168e | ||
|
|
fc8ca57f8c | ||
|
|
7e4bba2d55 | ||
|
|
7e635f9be4 | ||
|
|
e9406a20f2 | ||
|
|
de7729cec8 | ||
|
|
d60e48849b | ||
|
|
908df5a7bb | ||
|
|
c1952afb94 | ||
|
|
7a22e8f4dd | ||
|
|
3ac0da2cdd | ||
|
|
eb816c4cc6 | ||
|
|
64d8bf4fba | ||
|
|
ae6ee95973 | ||
|
|
e9051dc30a | ||
|
|
b6c7c53c3a | ||
|
|
f36bc61fc7 | ||
|
|
c56e0b9dac | ||
|
|
1deb08bf75 | ||
|
|
b30d7a8252 | ||
|
|
b03e11c18d | ||
|
|
bf7d22a794 | ||
|
|
fb57a8a3b5 | ||
|
|
0d625797b0 | ||
|
|
6777fbf229 | ||
|
|
23f1f79eff | ||
|
|
a5af104d53 | ||
|
|
38d94698ce | ||
|
|
5ba28ef599 | ||
|
|
a3486cc5b3 | ||
|
|
5ab322ab1d | ||
|
|
4f26bdd535 | ||
|
|
88f76e4355 | ||
|
|
a464d8cb19 | ||
|
|
0f596dce8b | ||
|
|
60270b20b3 | ||
|
|
4003a8d2b6 | ||
|
|
89843d6f37 | ||
|
|
256a52a5da | ||
|
|
c9b2bfe53c | ||
|
|
98cb36327e | ||
|
|
7d23e4882d | ||
|
|
1cc3a1d066 | ||
|
|
de0f7d2f01 | ||
|
|
aa48ffca2b | ||
|
|
802168cb5b | ||
|
|
6ace2e9f3d | ||
|
|
0bff360d22 | ||
|
|
e300acf109 | ||
|
|
14d8e12cdc | ||
|
|
d29411dba6 | ||
|
|
464663877c | ||
|
|
c3f769d48b | ||
|
|
f97536ed02 | ||
|
|
7686effc8c | ||
|
|
ee8385467b | ||
|
|
0a51d97684 | ||
|
|
67fc762eef | ||
|
|
8378795f5d | ||
|
|
98e6f1df4a | ||
|
|
674e35e5c5 | ||
|
|
b24ca44e6f | ||
|
|
e0f7fcd2ef | ||
|
|
c5bece64ce | ||
|
|
0034681412 | ||
|
|
bd5b99dc1c | ||
|
|
2feb802094 | ||
|
|
7b08a71c59 | ||
|
|
2a84e9c120 | ||
|
|
d854e8e991 | ||
|
|
0a363910d6 | ||
|
|
b23d5cd909 | ||
|
|
3b753aa69d | ||
|
|
492cd288bc | ||
|
|
47938c5082 | ||
|
|
97c4c9a366 | ||
|
|
d090e48544 | ||
|
|
314e4407a0 | ||
|
|
ed50e03957 | ||
|
|
dff7530cc5 | ||
|
|
19423c9644 | ||
|
|
42b3f1e59d | ||
|
|
1b77632fa8 | ||
|
|
867b7b1390 | ||
|
|
4c6ebde58c | ||
|
|
1e013d9e9a | ||
|
|
c56bc651b9 | ||
|
|
6cbdf45a7c | ||
|
|
715667e227 | ||
|
|
41de161555 | ||
|
|
1f1ea370c0 | ||
|
|
090cfc26f2 | ||
|
|
529890b5d2 | ||
|
|
d4a6ab146d | ||
|
|
e3f02879cf | ||
|
|
b52d6df777 | ||
|
|
9e671100ae | ||
|
|
7e801ea502 | ||
|
|
b68522f7d5 | ||
|
|
86852942e0 | ||
|
|
ea88d53e39 | ||
|
|
61f6a474e4 | ||
|
|
ec05c84f4d | ||
|
|
9e13c077e9 | ||
|
|
da8d315e77 | ||
|
|
82af9af1e1 | ||
|
|
cb67e3ae63 | ||
|
|
82d15c4dc2 | ||
|
|
6d048e2cee | ||
|
|
87bd80eea1 | ||
|
|
80e442e396 | ||
|
|
489ad375bd | ||
|
|
c420196e73 | ||
|
|
cc6d8d5f8b | ||
|
|
24f47bc58b | ||
|
|
c769c074e0 | ||
|
|
2ecb8eb034 | ||
|
|
6827c100c3 | ||
|
|
c402acd1bd | ||
|
|
c4ec2509fa | ||
|
|
0f382586ce | ||
|
|
9c2f12ecb1 | ||
|
|
12da117cab | ||
|
|
ef48f4b48e | ||
|
|
aae6db52b5 |
@@ -1,4 +1,4 @@
|
|||||||
name: build-docs
|
name: build-documentation
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
@@ -11,4 +11,4 @@ jobs:
|
|||||||
- env:
|
- env:
|
||||||
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
gh workflow run --repo Froxlor/Documentation build-docs -f ref=${{github.ref_name}}
|
gh workflow run --repo Froxlor/Documentation build-and-deploy.yml -f type=tags ref=${{github.ref_name}}
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@ install/update.log
|
|||||||
install/*.json
|
install/*.json
|
||||||
lib/userdata.inc.php
|
lib/userdata.inc.php
|
||||||
lib/userdata.inc.php.bak
|
lib/userdata.inc.php.bak
|
||||||
|
lib/config.inc.php
|
||||||
logs/*
|
logs/*
|
||||||
!logs/index.html
|
!logs/index.html
|
||||||
.buildpath
|
.buildpath
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ May be found in [COPYING](COPYING)
|
|||||||
### Tarball
|
### Tarball
|
||||||
https://files.froxlor.org/releases/froxlor-latest.tar.gz [MD5](https://files.froxlor.org/releases/froxlor-latest.tar.gz.md5) [SHA1](https://files.froxlor.org/releases/froxlor-latest.tar.gz.sha1)
|
https://files.froxlor.org/releases/froxlor-latest.tar.gz [MD5](https://files.froxlor.org/releases/froxlor-latest.tar.gz.md5) [SHA1](https://files.froxlor.org/releases/froxlor-latest.tar.gz.sha1)
|
||||||
|
|
||||||
### Debian / Ubutnu repository
|
### Debian / Ubuntu repository
|
||||||
|
|
||||||
[HowTo](https://docs.froxlor.org/latest/general/installation/apt-package.html)
|
[HowTo](https://docs.froxlor.org/latest/general/installation/apt-package.html)
|
||||||
|
|
||||||
|
|||||||
@@ -269,7 +269,8 @@ return [
|
|||||||
'traffic' => lng('menue.traffic.traffic'),
|
'traffic' => lng('menue.traffic.traffic'),
|
||||||
'traffic.http' => lng('menue.traffic.traffic') . " / HTTP",
|
'traffic.http' => lng('menue.traffic.traffic') . " / HTTP",
|
||||||
'traffic.ftp' => lng('menue.traffic.traffic') . " / FTP",
|
'traffic.ftp' => lng('menue.traffic.traffic') . " / FTP",
|
||||||
'traffic.mail' => lng('menue.traffic.traffic') . " / Mail"
|
'traffic.mail' => lng('menue.traffic.traffic') . " / Mail",
|
||||||
|
'misc.documentation' => lng('admin.documentation'),
|
||||||
],
|
],
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
|
|||||||
@@ -138,6 +138,26 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
|
'system_req_limit_per_interval' => [
|
||||||
|
'label' => lng('serversettings.req_limit_per_interval'),
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'req_limit_per_interval',
|
||||||
|
'type' => 'number',
|
||||||
|
'min' => 30,
|
||||||
|
'default' => 60,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'advanced_mode' => true
|
||||||
|
],
|
||||||
|
'system_req_limit_interval' => [
|
||||||
|
'label' => lng('serversettings.req_limit_interval'),
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'req_limit_interval',
|
||||||
|
'type' => 'number',
|
||||||
|
'min' => 5,
|
||||||
|
'default' => 60,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'advanced_mode' => true
|
||||||
|
],
|
||||||
'customer_accountprefix' => [
|
'customer_accountprefix' => [
|
||||||
'label' => lng('serversettings.accountprefix'),
|
'label' => lng('serversettings.accountprefix'),
|
||||||
'settinggroup' => 'customer',
|
'settinggroup' => 'customer',
|
||||||
|
|||||||
@@ -109,7 +109,19 @@ return [
|
|||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'update_channel' => [
|
'api_customer_default' => [
|
||||||
|
'label' => lng('serversettings.api_customer_default'),
|
||||||
|
'settinggroup' => 'api',
|
||||||
|
'varname' => 'customer_default',
|
||||||
|
'type' => 'select',
|
||||||
|
'default' => 1,
|
||||||
|
'select_var' => [
|
||||||
|
1 => lng('panel.yes'),
|
||||||
|
0 => lng('panel.no')
|
||||||
|
],
|
||||||
|
'save_method' => 'storeSettingField'
|
||||||
|
],
|
||||||
|
'system_update_channel' => [
|
||||||
'label' => lng('serversettings.update_channel'),
|
'label' => lng('serversettings.update_channel'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'update_channel',
|
'varname' => 'update_channel',
|
||||||
@@ -122,7 +134,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_validatedomain' => [
|
'system_validate_domain' => [
|
||||||
'label' => lng('serversettings.validate_domain'),
|
'label' => lng('serversettings.validate_domain'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'validate_domain',
|
'varname' => 'validate_domain',
|
||||||
@@ -307,7 +319,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'hide_incompatible_settings' => [
|
'system_hide_incompatible_settings' => [
|
||||||
'label' => lng('serversettings.hide_incompatible_settings'),
|
'label' => lng('serversettings.hide_incompatible_settings'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'hide_incompatible_settings',
|
'varname' => 'hide_incompatible_settings',
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ return [
|
|||||||
'string_regexp' => '/^(([a-z0-9\-\._]+, ?)*[a-z0-9\-\._]+)?$/i',
|
'string_regexp' => '/^(([a-z0-9\-\._]+, ?)*[a-z0-9\-\._]+)?$/i',
|
||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingClearCertificates',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
/**
|
/**
|
||||||
@@ -154,7 +154,7 @@ return [
|
|||||||
/**
|
/**
|
||||||
* FCGID
|
* FCGID
|
||||||
*/
|
*/
|
||||||
'system_mod_fcgid_enabled_ownvhost' => [
|
'system_mod_fcgid_ownvhost' => [
|
||||||
'label' => lng('serversettings.mod_fcgid_ownvhost'),
|
'label' => lng('serversettings.mod_fcgid_ownvhost'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'mod_fcgid_ownvhost',
|
'varname' => 'mod_fcgid_ownvhost',
|
||||||
@@ -224,7 +224,7 @@ return [
|
|||||||
/**
|
/**
|
||||||
* php-fpm
|
* php-fpm
|
||||||
*/
|
*/
|
||||||
'system_phpfpm_enabled_ownvhost' => [
|
'phpfpm_enabled_ownvhost' => [
|
||||||
'label' => lng('phpfpm.ownvhost'),
|
'label' => lng('phpfpm.ownvhost'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'enabled_ownvhost',
|
'varname' => 'enabled_ownvhost',
|
||||||
@@ -237,7 +237,7 @@ return [
|
|||||||
]),
|
]),
|
||||||
'requires_reconf' => ['system:php-fpm']
|
'requires_reconf' => ['system:php-fpm']
|
||||||
],
|
],
|
||||||
'system_phpfpm_httpuser' => [
|
'phpfpm_vhost_httpuser' => [
|
||||||
'label' => lng('phpfpm.vhost_httpuser'),
|
'label' => lng('phpfpm.vhost_httpuser'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'vhost_httpuser',
|
'varname' => 'vhost_httpuser',
|
||||||
@@ -250,7 +250,7 @@ return [
|
|||||||
]),
|
]),
|
||||||
'requires_reconf' => ['system:php-fpm']
|
'requires_reconf' => ['system:php-fpm']
|
||||||
],
|
],
|
||||||
'system_phpfpm_httpgroup' => [
|
'phpfpm_vhost_httpgroup' => [
|
||||||
'label' => lng('phpfpm.vhost_httpgroup'),
|
'label' => lng('phpfpm.vhost_httpgroup'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'vhost_httpgroup',
|
'varname' => 'vhost_httpgroup',
|
||||||
@@ -263,7 +263,7 @@ return [
|
|||||||
]),
|
]),
|
||||||
'requires_reconf' => ['system:php-fpm']
|
'requires_reconf' => ['system:php-fpm']
|
||||||
],
|
],
|
||||||
'system_phpfpm_defaultini_ownvhost' => [
|
'phpfpm_vhost_defaultini' => [
|
||||||
'label' => lng('serversettings.mod_fcgid.defaultini_ownvhost'),
|
'label' => lng('serversettings.mod_fcgid.defaultini_ownvhost'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'vhost_defaultini',
|
'varname' => 'vhost_defaultini',
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ return [
|
|||||||
'apache2'
|
'apache2'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_apache_itksupport' => [
|
'system_apacheitksupport' => [
|
||||||
'label' => lng('serversettings.apache_itksupport'),
|
'label' => lng('serversettings.apache_itksupport'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'apacheitksupport',
|
'varname' => 'apacheitksupport',
|
||||||
@@ -229,7 +229,7 @@ return [
|
|||||||
'nginx'
|
'nginx'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_customersslpath' => [
|
'system_customer_ssl_path' => [
|
||||||
'label' => lng('serversettings.customerssl_directory'),
|
'label' => lng('serversettings.customerssl_directory'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'customer_ssl_path',
|
'varname' => 'customer_ssl_path',
|
||||||
@@ -287,7 +287,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_apache_globaldiropt' => [
|
'system_apacheglobaldiropt' => [
|
||||||
'label' => lng('serversettings.apache_globaldiropt'),
|
'label' => lng('serversettings.apache_globaldiropt'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'apacheglobaldiropt',
|
'varname' => 'apacheglobaldiropt',
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ return [
|
|||||||
'title' => lng('admin.sslsettings'),
|
'title' => lng('admin.sslsettings'),
|
||||||
'icon' => 'fa-solid fa-shield',
|
'icon' => 'fa-solid fa-shield',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'system_ssl_enabled' => [
|
'system_use_ssl' => [
|
||||||
'label' => lng('serversettings.ssl.use_ssl'),
|
'label' => lng('serversettings.ssl.use_ssl'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'use_ssl',
|
'varname' => 'use_ssl',
|
||||||
@@ -180,7 +180,9 @@ return [
|
|||||||
'letsencrypt' => 'Let\'s Encrypt (Live)',
|
'letsencrypt' => 'Let\'s Encrypt (Live)',
|
||||||
'buypass_test' => 'Buypass (Test / Staging)',
|
'buypass_test' => 'Buypass (Test / Staging)',
|
||||||
'buypass' => 'Buypass (Live)',
|
'buypass' => 'Buypass (Live)',
|
||||||
'zerossl' => 'ZeroSSL (Live)'
|
'zerossl' => 'ZeroSSL (Live)',
|
||||||
|
'google' => 'Google (Live)',
|
||||||
|
'google_test' => 'Google (Test / Staging)',
|
||||||
],
|
],
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
@@ -239,6 +241,16 @@ return [
|
|||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => true,
|
'default' => true,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
|
],
|
||||||
|
'system_le_domain_dnscheck_resolver' => [
|
||||||
|
'label' => lng('serversettings.le_domain_dnscheck_resolver'),
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'le_domain_dnscheck_resolver',
|
||||||
|
'type' => 'text',
|
||||||
|
'string_regexp' => '/^(([0-9]+ [a-z0-9\-\._]+, ?)*[0-9]+ [a-z0-9\-\._]+)?$/i',
|
||||||
|
'string_emptyallowed' => true,
|
||||||
|
'default' => '',
|
||||||
|
'save_method' => 'storeSettingField'
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ return [
|
|||||||
'lighttpd'
|
'lighttpd'
|
||||||
],
|
],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'system_mod_fcgid_enabled' => [
|
'system_mod_fcgid' => [
|
||||||
'label' => lng('serversettings.mod_fcgid'),
|
'label' => lng('serversettings.mod_fcgid'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'mod_fcgid',
|
'varname' => 'mod_fcgid',
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ return [
|
|||||||
'title' => lng('admin.phpfpm_settings'),
|
'title' => lng('admin.phpfpm_settings'),
|
||||||
'icon' => 'fa-brands fa-php',
|
'icon' => 'fa-brands fa-php',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'system_phpfpm_enabled' => [
|
'phpfpm_enabled' => [
|
||||||
'label' => lng('serversettings.phpfpm'),
|
'label' => lng('serversettings.phpfpm'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'enabled',
|
'varname' => 'enabled',
|
||||||
@@ -45,7 +45,7 @@ return [
|
|||||||
'overview_option' => true,
|
'overview_option' => true,
|
||||||
'requires_reconf' => ['http', 'system:php-fpm']
|
'requires_reconf' => ['http', 'system:php-fpm']
|
||||||
],
|
],
|
||||||
'system_phpfpm_defaultini' => [
|
'phpfpm_defaultini' => [
|
||||||
'label' => lng('serversettings.mod_fcgid.defaultini'),
|
'label' => lng('serversettings.mod_fcgid.defaultini'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'defaultini',
|
'varname' => 'defaultini',
|
||||||
@@ -57,7 +57,7 @@ return [
|
|||||||
],
|
],
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_phpfpm_aliasconfigdir' => [
|
'phpfpm_aliasconfigdir' => [
|
||||||
'label' => lng('serversettings.phpfpm_settings.aliasconfigdir'),
|
'label' => lng('serversettings.phpfpm_settings.aliasconfigdir'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'aliasconfigdir',
|
'varname' => 'aliasconfigdir',
|
||||||
@@ -67,7 +67,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_tmpdir' => [
|
'phpfpm_tmpdir' => [
|
||||||
'label' => lng('serversettings.mod_fcgid.tmpdir'),
|
'label' => lng('serversettings.mod_fcgid.tmpdir'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'tmpdir',
|
'varname' => 'tmpdir',
|
||||||
@@ -76,7 +76,7 @@ return [
|
|||||||
'default' => '/var/customers/tmp/',
|
'default' => '/var/customers/tmp/',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_phpfpm_peardir' => [
|
'phpfpm_peardir' => [
|
||||||
'label' => lng('serversettings.mod_fcgid.peardir'),
|
'label' => lng('serversettings.mod_fcgid.peardir'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'peardir',
|
'varname' => 'peardir',
|
||||||
@@ -88,7 +88,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_envpath' => [
|
'phpfpm_envpath' => [
|
||||||
'label' => lng('serversettings.phpfpm_settings.envpath'),
|
'label' => lng('serversettings.phpfpm_settings.envpath'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'envpath',
|
'varname' => 'envpath',
|
||||||
@@ -100,7 +100,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_fastcgi_ipcdir' => [
|
'phpfpm_fastcgi_ipcdir' => [
|
||||||
'label' => lng('serversettings.phpfpm_settings.ipcdir'),
|
'label' => lng('serversettings.phpfpm_settings.ipcdir'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'fastcgi_ipcdir',
|
'varname' => 'fastcgi_ipcdir',
|
||||||
@@ -110,7 +110,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_use_mod_proxy' => [
|
'phpfpm_use_mod_proxy' => [
|
||||||
'label' => lng('phpfpm.use_mod_proxy'),
|
'label' => lng('phpfpm.use_mod_proxy'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'use_mod_proxy',
|
'varname' => 'use_mod_proxy',
|
||||||
@@ -119,7 +119,7 @@ return [
|
|||||||
'visible' => Settings::Get('system.apache24'),
|
'visible' => Settings::Get('system.apache24'),
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_phpfpm_ini_flags' => [
|
'phpfpm_ini_flags' => [
|
||||||
'label' => lng('phpfpm.ini_flags'),
|
'label' => lng('phpfpm.ini_flags'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'ini_flags',
|
'varname' => 'ini_flags',
|
||||||
@@ -128,7 +128,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_ini_values' => [
|
'phpfpm_ini_values' => [
|
||||||
'label' => lng('phpfpm.ini_values'),
|
'label' => lng('phpfpm.ini_values'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'ini_values',
|
'varname' => 'ini_values',
|
||||||
@@ -137,7 +137,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_ini_admin_flags' => [
|
'phpfpm_ini_admin_flags' => [
|
||||||
'label' => lng('phpfpm.ini_admin_flags'),
|
'label' => lng('phpfpm.ini_admin_flags'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'ini_admin_flags',
|
'varname' => 'ini_admin_flags',
|
||||||
@@ -146,7 +146,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_ini_admin_values' => [
|
'phpfpm_ini_admin_values' => [
|
||||||
'label' => lng('phpfpm.ini_admin_values'),
|
'label' => lng('phpfpm.ini_admin_values'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'ini_admin_values',
|
'varname' => 'ini_admin_values',
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ return [
|
|||||||
'title' => lng('admin.perl_settings'),
|
'title' => lng('admin.perl_settings'),
|
||||||
'icon' => 'fa-solid fa-code',
|
'icon' => 'fa-solid fa-code',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'perl_path' => [
|
'system_perl_path' => [
|
||||||
'label' => lng('serversettings.perl_path'),
|
'label' => lng('serversettings.perl_path'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'perl_path',
|
'varname' => 'perl_path',
|
||||||
@@ -40,7 +40,7 @@ return [
|
|||||||
'lighttpd'
|
'lighttpd'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_perl_suexecworkaround' => [
|
'perl_suexecworkaround' => [
|
||||||
'label' => lng('serversettings.perl.suexecworkaround'),
|
'label' => lng('serversettings.perl.suexecworkaround'),
|
||||||
'settinggroup' => 'perl',
|
'settinggroup' => 'perl',
|
||||||
'varname' => 'suexecworkaround',
|
'varname' => 'suexecworkaround',
|
||||||
@@ -51,7 +51,7 @@ return [
|
|||||||
'apache2'
|
'apache2'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_perl_suexeccgipath' => [
|
'perl_suexecpath' => [
|
||||||
'label' => lng('serversettings.perl.suexeccgipath'),
|
'label' => lng('serversettings.perl.suexeccgipath'),
|
||||||
'settinggroup' => 'perl',
|
'settinggroup' => 'perl',
|
||||||
'varname' => 'suexecpath',
|
'varname' => 'suexecpath',
|
||||||
@@ -63,7 +63,7 @@ return [
|
|||||||
'apache2'
|
'apache2'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'perl_server' => [
|
'serversettings_perl_server' => [
|
||||||
'label' => lng('serversettings.perl_server'),
|
'label' => lng('serversettings.perl_server'),
|
||||||
'settinggroup' => 'serversettings',
|
'settinggroup' => 'serversettings',
|
||||||
'varname' => 'perl_server',
|
'varname' => 'perl_server',
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ return [
|
|||||||
'default' => 100,
|
'default' => 100,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_catchall_enabled' => [
|
'catchall_catchall_enabled' => [
|
||||||
'label' => lng('serversettings.catchall_enabled'),
|
'label' => lng('serversettings.catchall_enabled'),
|
||||||
'settinggroup' => 'catchall',
|
'settinggroup' => 'catchall',
|
||||||
'varname' => 'catchall_enabled',
|
'varname' => 'catchall_enabled',
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ return [
|
|||||||
'title' => lng('admin.ftpserversettings'),
|
'title' => lng('admin.ftpserversettings'),
|
||||||
'icon' => 'fa-solid fa-arrow-right-arrow-left',
|
'icon' => 'fa-solid fa-arrow-right-arrow-left',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'ftpserver' => [
|
'system_ftpserver' => [
|
||||||
'label' => lng('admin.ftpserver'),
|
'label' => lng('admin.ftpserver'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'ftpserver',
|
'varname' => 'ftpserver',
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ return [
|
|||||||
'title' => lng('admin.nameserversettings'),
|
'title' => lng('admin.nameserversettings'),
|
||||||
'icon' => 'fa-solid fa-globe',
|
'icon' => 'fa-solid fa-globe',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'nameserver_enable' => [
|
'system_bind_enable' => [
|
||||||
'label' => lng('serversettings.bindenable'),
|
'label' => lng('serversettings.bindenable'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'bind_enable',
|
'varname' => 'bind_enable',
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ return [
|
|||||||
'title' => lng('admin.dkimsettings'),
|
'title' => lng('admin.dkimsettings'),
|
||||||
'icon' => 'fa-solid fa-fingerprint',
|
'icon' => 'fa-solid fa-fingerprint',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'dkim_enabled' => [
|
'dkim_use_dkim' => [
|
||||||
'label' => lng('dkim.use_dkim'),
|
'label' => lng('dkim.use_dkim'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'use_dkim',
|
'varname' => 'use_dkim',
|
||||||
@@ -40,7 +40,7 @@ return [
|
|||||||
'save_method' => 'storeSettingFieldInsertBindTask',
|
'save_method' => 'storeSettingFieldInsertBindTask',
|
||||||
'overview_option' => true
|
'overview_option' => true
|
||||||
],
|
],
|
||||||
'dkim_prefix' => [
|
'dkim_dkim_prefix' => [
|
||||||
'label' => lng('dkim.dkim_prefix'),
|
'label' => lng('dkim.dkim_prefix'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_prefix',
|
'varname' => 'dkim_prefix',
|
||||||
@@ -59,7 +59,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'dkim_domains' => [
|
'dkim_dkim_domains' => [
|
||||||
'label' => lng('dkim.dkim_domains'),
|
'label' => lng('dkim.dkim_domains'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_domains',
|
'varname' => 'dkim_domains',
|
||||||
@@ -68,7 +68,7 @@ return [
|
|||||||
'default' => 'domains',
|
'default' => 'domains',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'dkim_dkimkeys' => [
|
'dkim_dkim_dkimkeys' => [
|
||||||
'label' => lng('dkim.dkim_dkimkeys'),
|
'label' => lng('dkim.dkim_dkimkeys'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_dkimkeys',
|
'varname' => 'dkim_dkimkeys',
|
||||||
@@ -77,7 +77,7 @@ return [
|
|||||||
'default' => 'dkim-keys.conf',
|
'default' => 'dkim-keys.conf',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'dkim_algorithm' => [
|
'dkim_dkim_algorithm' => [
|
||||||
'label' => lng('dkim.dkim_algorithm'),
|
'label' => lng('dkim.dkim_algorithm'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_algorithm',
|
'varname' => 'dkim_algorithm',
|
||||||
@@ -92,7 +92,7 @@ return [
|
|||||||
'save_method' => 'storeSettingFieldInsertBindTask',
|
'save_method' => 'storeSettingFieldInsertBindTask',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'dkim_servicetype' => [
|
'dkim_dkim_servicetype' => [
|
||||||
'label' => lng('dkim.dkim_servicetype'),
|
'label' => lng('dkim.dkim_servicetype'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_servicetype',
|
'varname' => 'dkim_servicetype',
|
||||||
@@ -105,7 +105,7 @@ return [
|
|||||||
'save_method' => 'storeSettingFieldInsertBindTask',
|
'save_method' => 'storeSettingFieldInsertBindTask',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'dkim_keylength' => [
|
'dkim_dkim_keylength' => [
|
||||||
'label' => [
|
'label' => [
|
||||||
'title' => lng('dkim.dkim_keylength.title'),
|
'title' => lng('dkim.dkim_keylength.title'),
|
||||||
'description' => lng('dkim.dkim_keylength.description', [Settings::Get('dkim.dkim_prefix')])
|
'description' => lng('dkim.dkim_keylength.description', [Settings::Get('dkim.dkim_prefix')])
|
||||||
@@ -120,7 +120,7 @@ return [
|
|||||||
],
|
],
|
||||||
'save_method' => 'storeSettingFieldInsertBindTask'
|
'save_method' => 'storeSettingFieldInsertBindTask'
|
||||||
],
|
],
|
||||||
'dkim_notes' => [
|
'dkim_dkim_notes' => [
|
||||||
'label' => lng('dkim.dkim_notes'),
|
'label' => lng('dkim.dkim_notes'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_notes',
|
'varname' => 'dkim_notes',
|
||||||
@@ -130,7 +130,7 @@ return [
|
|||||||
'save_method' => 'storeSettingFieldInsertBindTask',
|
'save_method' => 'storeSettingFieldInsertBindTask',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'dkimrestart_command' => [
|
'dkim_dkimrestart_command' => [
|
||||||
'label' => lng('dkim.dkimrestart_command'),
|
'label' => lng('dkim.dkimrestart_command'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkimrestart_command',
|
'varname' => 'dkimrestart_command',
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ return [
|
|||||||
'title' => lng('admin.spfsettings'),
|
'title' => lng('admin.spfsettings'),
|
||||||
'icon' => 'fa-solid fa-clipboard-check',
|
'icon' => 'fa-solid fa-clipboard-check',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'use_spf' => [
|
'spf_use_spf' => [
|
||||||
'label' => lng('spf.use_spf'),
|
'label' => lng('spf.use_spf'),
|
||||||
'settinggroup' => 'spf',
|
'settinggroup' => 'spf',
|
||||||
'varname' => 'use_spf',
|
'varname' => 'use_spf',
|
||||||
@@ -38,7 +38,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'overview_option' => true
|
'overview_option' => true
|
||||||
],
|
],
|
||||||
'spf_entry' => [
|
'spf_spf_entry' => [
|
||||||
'label' => lng('spf.spf_entry'),
|
'label' => lng('spf.spf_entry'),
|
||||||
'settinggroup' => 'spf',
|
'settinggroup' => 'spf',
|
||||||
'varname' => 'spf_entry',
|
'varname' => 'spf_entry',
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ return [
|
|||||||
'icon' => 'fa-solid fa-sliders',
|
'icon' => 'fa-solid fa-sliders',
|
||||||
'advanced_mode' => true,
|
'advanced_mode' => true,
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'diskquota_enabled' => [
|
'system_diskquota_enabled' => [
|
||||||
'label' => lng('serversettings.diskquota_enabled'),
|
'label' => lng('serversettings.diskquota_enabled'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'diskquota_enabled',
|
'varname' => 'diskquota_enabled',
|
||||||
@@ -39,7 +39,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'overview_option' => true
|
'overview_option' => true
|
||||||
],
|
],
|
||||||
'diskquota_repquota_path' => [
|
'system_diskquota_repquota_path' => [
|
||||||
'label' => lng('serversettings.diskquota_repquota_path.description'),
|
'label' => lng('serversettings.diskquota_repquota_path.description'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'diskquota_repquota_path',
|
'varname' => 'diskquota_repquota_path',
|
||||||
@@ -47,7 +47,7 @@ return [
|
|||||||
'default' => '/usr/sbin/repquota',
|
'default' => '/usr/sbin/repquota',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'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',
|
||||||
@@ -55,7 +55,7 @@ return [
|
|||||||
'default' => '/usr/bin/quotatool',
|
'default' => '/usr/bin/quotatool',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'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',
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ if ($userinfo['change_serversettings'] == '1') {
|
|||||||
|
|
||||||
if ($distribution != "" && isset($_POST['finish'])) {
|
if ($distribution != "" && isset($_POST['finish'])) {
|
||||||
unset($_POST['finish']);
|
unset($_POST['finish']);
|
||||||
|
unset($_POST['csrf_token']);
|
||||||
$params = $_POST;
|
$params = $_POST;
|
||||||
$params['distro'] = $distribution;
|
$params['distro'] = $distribution;
|
||||||
$params['system'] = [];
|
$params['system'] = [];
|
||||||
@@ -121,8 +122,6 @@ if ($userinfo['change_serversettings'] == '1') {
|
|||||||
'distribution' => $distribution
|
'distribution' => $distribution
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// @fixme check set distribution from settings
|
|
||||||
|
|
||||||
$cfg_formfield = [
|
$cfg_formfield = [
|
||||||
'config' => [
|
'config' => [
|
||||||
'title' => lng('admin.configfiles.serverconfiguration'),
|
'title' => lng('admin.configfiles.serverconfiguration'),
|
||||||
|
|||||||
@@ -282,6 +282,12 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$openbasedir = [
|
||||||
|
0 => lng('domain.docroot'),
|
||||||
|
1 => lng('domain.homedir'),
|
||||||
|
2 => lng('domain.docparent')
|
||||||
|
];
|
||||||
|
|
||||||
// create serveralias options
|
// create serveralias options
|
||||||
$serveraliasoptions = [
|
$serveraliasoptions = [
|
||||||
0 => lng('domains.serveraliasoption_wildcard'),
|
0 => lng('domains.serveraliasoption_wildcard'),
|
||||||
@@ -545,6 +551,12 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
$result['temporary_ssl_redirect'] = $result['ssl_redirect'];
|
$result['temporary_ssl_redirect'] = $result['ssl_redirect'];
|
||||||
$result['ssl_redirect'] = ($result['ssl_redirect'] == 0 ? 0 : 1);
|
$result['ssl_redirect'] = ($result['ssl_redirect'] == 0 ? 0 : 1);
|
||||||
|
|
||||||
|
$openbasedir = [
|
||||||
|
0 => lng('domain.docroot'),
|
||||||
|
1 => lng('domain.homedir'),
|
||||||
|
2 => lng('domain.docparent')
|
||||||
|
];
|
||||||
|
|
||||||
$serveraliasoptions = [
|
$serveraliasoptions = [
|
||||||
0 => lng('domains.serveraliasoption_wildcard'),
|
0 => lng('domains.serveraliasoption_wildcard'),
|
||||||
1 => lng('domains.serveraliasoption_www'),
|
1 => lng('domains.serveraliasoption_www'),
|
||||||
|
|||||||
@@ -43,12 +43,6 @@ use PHPMailer\PHPMailer\PHPMailer;
|
|||||||
const AREA = 'admin';
|
const AREA = 'admin';
|
||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
// get sql-root access data
|
|
||||||
Database::needRoot(true);
|
|
||||||
Database::needSqlData();
|
|
||||||
$sql_root = Database::getSqlData();
|
|
||||||
Database::needRoot(false);
|
|
||||||
|
|
||||||
if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
|
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);
|
||||||
|
|||||||
@@ -253,6 +253,9 @@ if ($action == '') {
|
|||||||
if (isset($_POST['prepare']) && $_POST['prepare'] == 'prepare') {
|
if (isset($_POST['prepare']) && $_POST['prepare'] == 'prepare') {
|
||||||
// email templates
|
// email templates
|
||||||
$language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
|
$language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
|
||||||
|
if (!array_key_exists($language, $languages)) {
|
||||||
|
Response::standardError('templatelanguageinvalid');
|
||||||
|
}
|
||||||
$template = Validate::validate($_POST['template'], 'template');
|
$template = Validate::validate($_POST['template'], 'template');
|
||||||
|
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
@@ -288,6 +291,9 @@ if ($action == '') {
|
|||||||
} elseif (isset($_POST['send']) && $_POST['send'] == 'send' && !isset($_POST['filesend'])) {
|
} elseif (isset($_POST['send']) && $_POST['send'] == 'send' && !isset($_POST['filesend'])) {
|
||||||
// email templates
|
// email templates
|
||||||
$language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
|
$language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
|
||||||
|
if (!array_key_exists($language, $languages)) {
|
||||||
|
Response::standardError('templatelanguageinvalid');
|
||||||
|
}
|
||||||
$template = Validate::validate($_POST['template'], 'template');
|
$template = Validate::validate($_POST['template'], 'template');
|
||||||
$subject = Validate::validate($_POST['subject'], 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate');
|
$subject = Validate::validate($_POST['subject'], 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate');
|
||||||
$mailbody = Validate::validate($_POST['mailbody'], 'mailbody', '/^[^\0]+$/', 'nomailbodycreate');
|
$mailbody = Validate::validate($_POST['mailbody'], 'mailbody', '/^[^\0]+$/', 'nomailbodycreate');
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ use Froxlor\Cli\UpdateCommand;
|
|||||||
use Froxlor\Cli\InstallCommand;
|
use Froxlor\Cli\InstallCommand;
|
||||||
use Froxlor\Cli\MasterCron;
|
use Froxlor\Cli\MasterCron;
|
||||||
use Froxlor\Cli\UserCommand;
|
use Froxlor\Cli\UserCommand;
|
||||||
|
use Froxlor\Cli\ValidateAcmeWebroot;
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
|
|
||||||
// validate correct php version
|
// validate correct php version
|
||||||
@@ -59,4 +60,5 @@ $application->add(new UpdateCommand());
|
|||||||
$application->add(new InstallCommand());
|
$application->add(new InstallCommand());
|
||||||
$application->add(new MasterCron());
|
$application->add(new MasterCron());
|
||||||
$application->add(new UserCommand());
|
$application->add(new UserCommand());
|
||||||
|
$application->add(new ValidateAcmeWebroot());
|
||||||
$application->run();
|
$application->run();
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"ext-fileinfo": "*",
|
"ext-fileinfo": "*",
|
||||||
"ext-gmp": "*",
|
"ext-gmp": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
"phpmailer/phpmailer": "~6.0",
|
"phpmailer/phpmailer": "~6.0",
|
||||||
"monolog/monolog": "^1.24",
|
"monolog/monolog": "^1.24",
|
||||||
"robthree/twofactorauth": "^1.6",
|
"robthree/twofactorauth": "^1.6",
|
||||||
@@ -52,7 +53,8 @@
|
|||||||
"voku/anti-xss": "^4.1",
|
"voku/anti-xss": "^4.1",
|
||||||
"twig/twig": "^3.3",
|
"twig/twig": "^3.3",
|
||||||
"erusev/parsedown": "^1.7",
|
"erusev/parsedown": "^1.7",
|
||||||
"symfony/console": "^5.4"
|
"symfony/console": "^5.4",
|
||||||
|
"pear/net_dns2": "^1.5"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9",
|
"phpunit/phpunit": "^9",
|
||||||
|
|||||||
836
composer.lock
generated
836
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -59,7 +59,6 @@ if ($page == 'overview' || $page == 'domains') {
|
|||||||
$domain_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.domains.php';
|
$domain_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.domains.php';
|
||||||
$collection = (new Collection(SubDomains::class, $userinfo))
|
$collection = (new Collection(SubDomains::class, $userinfo))
|
||||||
->withPagination($domain_list_data['domain_list']['columns'], $domain_list_data['domain_list']['default_sorting']);
|
->withPagination($domain_list_data['domain_list']['columns'], $domain_list_data['domain_list']['default_sorting']);
|
||||||
$parentDomainCollection = (new Collection(SubDomains::class, $userinfo, ['sql_search' => ['d.parentdomainid' => 0]]));
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,10 @@
|
|||||||
const AREA = 'customer';
|
const AREA = 'customer';
|
||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\Api\Commands\EmailAccounts as EmailAccounts;
|
use Froxlor\Api\Commands\EmailAccounts;
|
||||||
use Froxlor\Api\Commands\EmailForwarders as EmailForwarders;
|
use Froxlor\Api\Commands\EmailForwarders;
|
||||||
use Froxlor\Api\Commands\Emails as Emails;
|
use Froxlor\Api\Commands\Emails;
|
||||||
|
use Froxlor\Api\Commands\EmailDomains;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\PhpHelper;
|
use Froxlor\PhpHelper;
|
||||||
@@ -50,13 +51,50 @@ if (Settings::IsInList('panel.customer_hide_options', 'email') || $userinfo['ema
|
|||||||
$id = (int)Request::any('id');
|
$id = (int)Request::any('id');
|
||||||
|
|
||||||
if ($page == 'overview' || $page == 'emails') {
|
if ($page == 'overview' || $page == 'emails') {
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT COUNT(DISTINCT `domainid`) as maildomains FROM `" . TABLE_MAIL_VIRTUAL . "` WHERE `customerid`= :cid
|
||||||
|
");
|
||||||
|
$domain_count = Database::pexecute_first($result_stmt, [
|
||||||
|
"cid" => $userinfo['customerid']
|
||||||
|
]);
|
||||||
|
if ($domain_count['maildomains'] && $domain_count['maildomains'] > 1) {
|
||||||
|
try {
|
||||||
|
$emaildomain_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.emails_overview.php';
|
||||||
|
$collection = (new Collection(EmailDomains::class, $userinfo))
|
||||||
|
->withPagination($emaildomain_list_data['emaildomain_list']['columns'],
|
||||||
|
$emaildomain_list_data['emaildomain_list']['default_sorting']);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
UI::view('user/table.html.twig', [
|
||||||
|
'listing' => Listing::format($collection, $emaildomain_list_data, 'emaildomain_list'),
|
||||||
|
'actions_links' => CurrentUser::canAddResource('emails') ? [
|
||||||
|
[
|
||||||
|
'href' => $linker->getLink(['section' => 'email', 'page' => 'email_domain', 'action' => 'add']),
|
||||||
|
'label' => lng('emails.emails_add')
|
||||||
|
]
|
||||||
|
] : null,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
// only emails for one domain -> show email address listing directly
|
||||||
|
$page = 'email_domain';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($page == 'email_domain') {
|
||||||
|
$email_domainid = Request::any('domainid', 0);
|
||||||
if ($action == '') {
|
if ($action == '') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_email::emails");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_email::emails");
|
||||||
|
|
||||||
|
$sql_search = [];
|
||||||
|
if ($email_domainid > 0) {
|
||||||
|
$sql_search = ['sql_search' => ['m.domainid' => ['op' => '=', 'value' => $email_domainid]]];
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
$email_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.emails.php';
|
$email_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.emails.php';
|
||||||
$collection = (new Collection(Emails::class, $userinfo))
|
$collection = (new Collection(Emails::class, $userinfo, $sql_search))
|
||||||
->withPagination($email_list_data['email_list']['columns'], $email_list_data['email_list']['default_sorting']);
|
->withPagination($email_list_data['email_list']['columns'],
|
||||||
|
$email_list_data['email_list']['default_sorting']);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
@@ -71,13 +109,22 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
]);
|
]);
|
||||||
$emaildomains_count = $result2['emaildomains'];
|
$emaildomains_count = $result2['emaildomains'];
|
||||||
|
|
||||||
$actions_links = false;
|
$actions_links = [];
|
||||||
|
if ($email_domainid > 0) {
|
||||||
|
$actions_links[] = [
|
||||||
|
'class' => 'btn-outline-primary',
|
||||||
|
'href' => $linker->getLink([
|
||||||
|
'section' => 'email',
|
||||||
|
'page' => 'emails',
|
||||||
|
]),
|
||||||
|
'label' => lng('emails.back_to_overview'),
|
||||||
|
'icon' => 'fa-solid fa-reply'
|
||||||
|
];
|
||||||
|
}
|
||||||
if (CurrentUser::canAddResource('emails')) {
|
if (CurrentUser::canAddResource('emails')) {
|
||||||
$actions_links = [
|
$actions_links[] = [
|
||||||
[
|
'href' => $linker->getLink(['section' => 'email', 'page' => 'email_domain', 'action' => 'add', 'domainid' => $email_domainid]),
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => $page, 'action' => 'add']),
|
|
||||||
'label' => lng('emails.emails_add')
|
'label' => lng('emails.emails_add')
|
||||||
]
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +192,11 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
"cid" => $userinfo['customerid']
|
"cid" => $userinfo['customerid']
|
||||||
]);
|
]);
|
||||||
$domains = [];
|
$domains = [];
|
||||||
|
$selected_domain = "";
|
||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
if ($email_domainid == $row['id']) {
|
||||||
|
$selected_domain = $row['domain'];
|
||||||
|
}
|
||||||
$domains[$row['domain']] = $idna_convert->decode($row['domain']);
|
$domains[$row['domain']] = $idna_convert->decode($row['domain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,11 +295,13 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} elseif ($page == 'accounts') {
|
} elseif ($page == 'accounts') {
|
||||||
|
$email_domainid = Request::any('domainid', 0);
|
||||||
if ($action == 'add' && $id != 0) {
|
if ($action == 'add' && $id != 0) {
|
||||||
if ($userinfo['email_accounts'] == '-1' || ($userinfo['email_accounts_used'] < $userinfo['email_accounts'])) {
|
if ($userinfo['email_accounts'] == '-1' || ($userinfo['email_accounts_used'] < $userinfo['email_accounts'])) {
|
||||||
try {
|
try {
|
||||||
@@ -267,7 +320,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -292,7 +346,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink([
|
'href' => $linker->getLink([
|
||||||
'section' => 'email',
|
'section' => 'email',
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]),
|
]),
|
||||||
@@ -301,7 +356,11 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => 'emails']),
|
'href' => $linker->getLink([
|
||||||
|
'section' => 'email',
|
||||||
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid
|
||||||
|
]),
|
||||||
'label' => lng('menue.email.emails'),
|
'label' => lng('menue.email.emails'),
|
||||||
'icon' => 'fa-solid fa-envelope'
|
'icon' => 'fa-solid fa-envelope'
|
||||||
]
|
]
|
||||||
@@ -332,7 +391,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -350,7 +410,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink([
|
'href' => $linker->getLink([
|
||||||
'section' => 'email',
|
'section' => 'email',
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]),
|
]),
|
||||||
@@ -359,7 +420,11 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => 'emails']),
|
'href' => $linker->getLink([
|
||||||
|
'section' => 'email',
|
||||||
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid
|
||||||
|
]),
|
||||||
'label' => lng('menue.email.emails'),
|
'label' => lng('menue.email.emails'),
|
||||||
'icon' => 'fa-solid fa-envelope'
|
'icon' => 'fa-solid fa-envelope'
|
||||||
]
|
]
|
||||||
@@ -385,7 +450,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -403,7 +469,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink([
|
'href' => $linker->getLink([
|
||||||
'section' => 'email',
|
'section' => 'email',
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]),
|
]),
|
||||||
@@ -412,7 +479,11 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => 'emails']),
|
'href' => $linker->getLink([
|
||||||
|
'section' => 'email',
|
||||||
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid
|
||||||
|
]),
|
||||||
'label' => lng('menue.email.emails'),
|
'label' => lng('menue.email.emails'),
|
||||||
'icon' => 'fa-solid fa-envelope'
|
'icon' => 'fa-solid fa-envelope'
|
||||||
]
|
]
|
||||||
@@ -438,7 +509,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -446,12 +518,14 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
HTML::askYesNoWithCheckbox('email_reallydelete_account', 'admin_customer_alsoremovemail', $filename, [
|
HTML::askYesNoWithCheckbox('email_reallydelete_account', 'admin_customer_alsoremovemail', $filename, [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => $action
|
'action' => $action
|
||||||
], $idna_convert->decode($result['email_full']));
|
], $idna_convert->decode($result['email_full']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($page == 'forwarders') {
|
} elseif ($page == 'forwarders') {
|
||||||
|
$email_domainid = Request::any('domainid', 0);
|
||||||
if ($action == 'add' && $id != 0) {
|
if ($action == 'add' && $id != 0) {
|
||||||
if ($userinfo['email_forwarders_used'] < $userinfo['email_forwarders'] || $userinfo['email_forwarders'] == '-1') {
|
if ($userinfo['email_forwarders_used'] < $userinfo['email_forwarders'] || $userinfo['email_forwarders'] == '-1') {
|
||||||
try {
|
try {
|
||||||
@@ -471,7 +545,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -489,7 +564,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink([
|
'href' => $linker->getLink([
|
||||||
'section' => 'email',
|
'section' => 'email',
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]),
|
]),
|
||||||
@@ -498,7 +574,11 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => 'emails']),
|
'href' => $linker->getLink([
|
||||||
|
'section' => 'email',
|
||||||
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid
|
||||||
|
]),
|
||||||
'label' => lng('menue.email.emails'),
|
'label' => lng('menue.email.emails'),
|
||||||
'icon' => 'fa-solid fa-envelope'
|
'icon' => 'fa-solid fa-envelope'
|
||||||
]
|
]
|
||||||
@@ -540,7 +620,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -549,6 +630,7 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'id' => $id,
|
'id' => $id,
|
||||||
'forwarderid' => $forwarderid,
|
'forwarderid' => $forwarderid,
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => $action
|
'action' => $action
|
||||||
], $idna_convert->decode($result['email_full']) . ' -> ' . $idna_convert->decode($forwarder));
|
], $idna_convert->decode($result['email_full']) . ' -> ' . $idna_convert->decode($forwarder));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ use Froxlor\UI\Response;
|
|||||||
use Froxlor\CurrentUser;
|
use Froxlor\CurrentUser;
|
||||||
|
|
||||||
// redirect if this customer page is hidden via settings
|
// redirect if this customer page is hidden via settings
|
||||||
if (Settings::IsInList('panel.customer_hide_options', 'ftp') || $userinfo['ftps'] == 0) {
|
if (Settings::IsInList('panel.customer_hide_options', 'ftp')) {
|
||||||
Response::redirectTo('customer_index.php');
|
Response::redirectTo('customer_index.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ if ($page == 'overview' || $page == 'accounts') {
|
|||||||
if (Settings::Get('customer.ftpatdomain') == '1') {
|
if (Settings::Get('customer.ftpatdomain') == '1') {
|
||||||
$domainlist = [];
|
$domainlist = [];
|
||||||
$result_domains_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
$result_domains_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE `customerid`= :customerid");
|
WHERE `customerid`= :customerid ORDER BY `domain` ASC");
|
||||||
Database::pexecute($result_domains_stmt, [
|
Database::pexecute($result_domains_stmt, [
|
||||||
"customerid" => $userinfo['customerid']
|
"customerid" => $userinfo['customerid']
|
||||||
]);
|
]);
|
||||||
@@ -127,7 +127,6 @@ if ($page == 'overview' || $page == 'accounts') {
|
|||||||
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$domainlist[$row_domain['domain']] = $idna_convert->decode($row_domain['domain']);
|
$domainlist[$row_domain['domain']] = $idna_convert->decode($row_domain['domain']);
|
||||||
}
|
}
|
||||||
sort($domainlist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::Get('system.allow_customer_shell') == '1') {
|
if (Settings::Get('system.allow_customer_shell') == '1') {
|
||||||
|
|||||||
@@ -115,10 +115,14 @@ if ($page == 'overview') {
|
|||||||
|
|
||||||
if ($usages) {
|
if ($usages) {
|
||||||
$userinfo['diskspace_bytes_used'] = $usages['webspace'] * 1024;
|
$userinfo['diskspace_bytes_used'] = $usages['webspace'] * 1024;
|
||||||
|
$userinfo['mailspace_used'] = $usages['mail'] * 1024;
|
||||||
|
$userinfo['dbspace_used'] = $usages['mysql'] * 1024;
|
||||||
$userinfo['total_bytes_used'] = ($usages['webspace'] + $usages['mail'] + $usages['mysql']) * 1024;
|
$userinfo['total_bytes_used'] = ($usages['webspace'] + $usages['mail'] + $usages['mysql']) * 1024;
|
||||||
} else {
|
} else {
|
||||||
$userinfo['diskspace_bytes_used'] = 0;
|
$userinfo['diskspace_bytes_used'] = 0;
|
||||||
$userinfo['total_bytes_used'] = 0;
|
$userinfo['total_bytes_used'] = 0;
|
||||||
|
$userinfo['mailspace_used'] = 0;
|
||||||
|
$userinfo['dbspace_used'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::twig()->addGlobal('userinfo', $userinfo);
|
UI::twig()->addGlobal('userinfo', $userinfo);
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ 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'] != '') {
|
||||||
Database::needRoot(true, $result['dbserver']);
|
Database::needRoot(true, $result['dbserver'], false);
|
||||||
Database::needSqlData();
|
Database::needSqlData();
|
||||||
$sql_root = Database::getSqlData();
|
$sql_root = Database::getSqlData();
|
||||||
Database::needRoot(false);
|
Database::needRoot(false);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ if ($action == 'add_record' && !empty($_POST)) {
|
|||||||
try {
|
try {
|
||||||
$dns_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/tablelisting.dns.php';
|
$dns_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/tablelisting.dns.php';
|
||||||
$collection = (new Collection(DomainZones::class, $userinfo, ['id' => $domain_id]))
|
$collection = (new Collection(DomainZones::class, $userinfo, ['id' => $domain_id]))
|
||||||
->withPagination($dns_list_data['dns_list']['columns'], $dns_list_data['dns_list']['default_sorting']);
|
->withPagination($dns_list_data['dns_list']['columns'], $dns_list_data['dns_list']['default_sorting'], ['domain_id='.$domain_id]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use Froxlor\Froxlor;
|
|||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
|
||||||
// This file is being included in admin_domains and customer_domains
|
// This file is being included in admin_domains and customer_domains
|
||||||
// and therefore does not need to require lib/init.php
|
// and therefore does not need to require lib/init.php
|
||||||
@@ -67,6 +68,11 @@ if (!empty($errid)) {
|
|||||||
$mail_body .= "User-Area: " . AREA . "\n";
|
$mail_body .= "User-Area: " . AREA . "\n";
|
||||||
$mail_body .= "Froxlor-version: " . Froxlor::VERSION . "\n";
|
$mail_body .= "Froxlor-version: " . Froxlor::VERSION . "\n";
|
||||||
$mail_body .= "DB-version: " . Froxlor::DBVERSION . "\n\n";
|
$mail_body .= "DB-version: " . Froxlor::DBVERSION . "\n\n";
|
||||||
|
try {
|
||||||
|
$mail_body .= "Database: " . Database::getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
$mail_body .= "End of report";
|
$mail_body .= "End of report";
|
||||||
$mail_html = nl2br($mail_body);
|
$mail_html = nl2br($mail_body);
|
||||||
|
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ CREATE TABLE `panel_customers` (
|
|||||||
`allowed_mysqlserver` text NOT NULL,
|
`allowed_mysqlserver` text NOT NULL,
|
||||||
PRIMARY KEY (`customerid`),
|
PRIMARY KEY (`customerid`),
|
||||||
UNIQUE KEY `loginname` (`loginname`)
|
UNIQUE KEY `loginname` (`loginname`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_databases`;
|
DROP TABLE IF EXISTS `panel_databases`;
|
||||||
@@ -642,7 +642,7 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'leprivatekey', 'unset'),
|
('system', 'leprivatekey', 'unset'),
|
||||||
('system', 'lepublickey', 'unset'),
|
('system', 'lepublickey', 'unset'),
|
||||||
('system', 'letsencryptca', 'letsencrypt'),
|
('system', 'letsencryptca', 'letsencrypt'),
|
||||||
('system', 'letsencryptchallengepath', '/var/www/froxlor'),
|
('system', 'letsencryptchallengepath', '/var/www/html/froxlor'),
|
||||||
('system', 'letsencryptkeysize', '4096'),
|
('system', 'letsencryptkeysize', '4096'),
|
||||||
('system', 'letsencryptreuseold', 0),
|
('system', 'letsencryptreuseold', 0),
|
||||||
('system', 'leenabled', '0'),
|
('system', 'leenabled', '0'),
|
||||||
@@ -670,6 +670,7 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'leaccount', ''),
|
('system', 'leaccount', ''),
|
||||||
('system', 'nssextrausers', '1'),
|
('system', 'nssextrausers', '1'),
|
||||||
('system', 'le_domain_dnscheck', '1'),
|
('system', 'le_domain_dnscheck', '1'),
|
||||||
|
('system', 'le_domain_dnscheck_resolver', '1.1.1.1'),
|
||||||
('system', 'ssl_protocols', 'TLSv1.2'),
|
('system', 'ssl_protocols', 'TLSv1.2'),
|
||||||
('system', 'tlsv13_cipher_list', ''),
|
('system', 'tlsv13_cipher_list', ''),
|
||||||
('system', 'honorcipherorder', '0'),
|
('system', 'honorcipherorder', '0'),
|
||||||
@@ -696,9 +697,12 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'distribution', ''),
|
('system', 'distribution', ''),
|
||||||
('system', 'update_channel', 'stable'),
|
('system', 'update_channel', 'stable'),
|
||||||
('system', 'updatecheck_data', ''),
|
('system', 'updatecheck_data', ''),
|
||||||
('system', 'update_notify_last', '2.0.2'),
|
('system', 'update_notify_last', '2.0.16'),
|
||||||
('system', 'traffictool', 'goaccess'),
|
('system', 'traffictool', 'goaccess'),
|
||||||
|
('system', 'req_limit_per_interval', 60),
|
||||||
|
('system', 'req_limit_interval', 60),
|
||||||
('api', 'enabled', '0'),
|
('api', 'enabled', '0'),
|
||||||
|
('api', 'customer_default', '1'),
|
||||||
('2fa', 'enabled', '1'),
|
('2fa', 'enabled', '1'),
|
||||||
('panel', 'decimal_places', '4'),
|
('panel', 'decimal_places', '4'),
|
||||||
('panel', 'adminmail', 'admin@SERVERNAME'),
|
('panel', 'adminmail', 'admin@SERVERNAME'),
|
||||||
@@ -740,8 +744,8 @@ opcache.validate_timestamps'),
|
|||||||
('panel', 'logo_overridetheme', '0'),
|
('panel', 'logo_overridetheme', '0'),
|
||||||
('panel', 'logo_overridecustom', '0'),
|
('panel', 'logo_overridecustom', '0'),
|
||||||
('panel', 'settings_mode', '0'),
|
('panel', 'settings_mode', '0'),
|
||||||
('panel', 'version', '2.0.2'),
|
('panel', 'version', '2.0.16'),
|
||||||
('panel', 'db_version', '202212060');
|
('panel', 'db_version', '202304260');
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_tasks`;
|
DROP TABLE IF EXISTS `panel_tasks`;
|
||||||
@@ -981,7 +985,9 @@ CREATE TABLE IF NOT EXISTS `domain_ssl_settings` (
|
|||||||
`ssl_cert_chainfile` mediumtext,
|
`ssl_cert_chainfile` mediumtext,
|
||||||
`ssl_csr_file` mediumtext,
|
`ssl_csr_file` mediumtext,
|
||||||
`ssl_fullchain_file` mediumtext,
|
`ssl_fullchain_file` mediumtext,
|
||||||
`expirationdate` datetime DEFAULT NULL,
|
`validfromdate` datetime DEFAULT NULL,
|
||||||
|
`validtodate` datetime DEFAULT NULL,
|
||||||
|
`issuer` varchar(255) NOT NULL default '',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY (`domainid`)
|
UNIQUE KEY (`domainid`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Froxlor\Http\RateLimiter;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\Install\Install;
|
use Froxlor\Install\Install;
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ require dirname(__DIR__) . '/lib/tables.inc.php';
|
|||||||
// init twig
|
// init twig
|
||||||
UI::initTwig(true);
|
UI::initTwig(true);
|
||||||
UI::sendHeaders();
|
UI::sendHeaders();
|
||||||
|
RateLimiter::run(true);
|
||||||
|
|
||||||
$installer = new Install();
|
$installer = new Install();
|
||||||
$installer->handle();
|
$installer->handle();
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\FileDir;
|
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Settings;
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Install\Update;
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
|
||||||
if (!defined('_CRON_UPDATE')) {
|
if (!defined('_CRON_UPDATE')) {
|
||||||
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
|
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
|
||||||
@@ -38,7 +38,6 @@ if (!defined('_CRON_UPDATE')) {
|
|||||||
|
|
||||||
// last 0.10.x release
|
// last 0.10.x release
|
||||||
if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
||||||
|
|
||||||
$update_to = '2.0.0-beta1';
|
$update_to = '2.0.0-beta1';
|
||||||
|
|
||||||
Update::showUpdateStep("Updating from 0.10.38.3 to " . $update_to, false);
|
Update::showUpdateStep("Updating from 0.10.38.3 to " . $update_to, false);
|
||||||
@@ -67,9 +66,10 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;";
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;";
|
||||||
Database::query($sql);
|
Database::query($sql);
|
||||||
// new customer allowed_mysqlserver field
|
// new customer allowed_mysqlserver field
|
||||||
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `allowed_mysqlserver` text NOT NULL;");
|
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ROW_FORMAT=DYNAMIC;");
|
||||||
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE COLUMN `allowed_phpconfigs` `allowed_phpconfigs` text NOT NULL;");
|
|
||||||
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE COLUMN `customernumber` `customernumber` varchar(100) NOT NULL default '';");
|
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE COLUMN `customernumber` `customernumber` varchar(100) NOT NULL default '';");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE COLUMN `allowed_phpconfigs` `allowed_phpconfigs` text NOT NULL;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `allowed_mysqlserver` text NOT NULL;");
|
||||||
$has_customer_table_update_200 = true;
|
$has_customer_table_update_200 = true;
|
||||||
// ftp_users adjustments
|
// ftp_users adjustments
|
||||||
Database::query("ALTER TABLE `" . TABLE_FTP_USERS . "` CHANGE COLUMN `password` `password` varchar(255) NOT NULL default '';");
|
Database::query("ALTER TABLE `" . TABLE_FTP_USERS . "` CHANGE COLUMN `password` `password` varchar(255) NOT NULL default '';");
|
||||||
@@ -82,7 +82,7 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` DROP COLUMN `domains_see_all`;");
|
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` DROP COLUMN `domains_see_all`;");
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
Update::showUpdateStep("Checking for multiple mysql-servers to allow acccess to customers for existing databases");
|
Update::showUpdateStep("Checking for multiple mysql-servers to allow access to customers for existing databases");
|
||||||
$dbservers_stmt = Database::query("
|
$dbservers_stmt = Database::query("
|
||||||
SELECT `customerid`,
|
SELECT `customerid`,
|
||||||
GROUP_CONCAT(DISTINCT `dbserver` SEPARATOR ',') as allowed_mysqlserver
|
GROUP_CONCAT(DISTINCT `dbserver` SEPARATOR ',') as allowed_mysqlserver
|
||||||
@@ -93,7 +93,8 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
if (isset($dbserver['allowed_mysqlserver']) && !empty($dbserver['allowed_mysqlserver'])) {
|
if (isset($dbserver['allowed_mysqlserver']) && !empty($dbserver['allowed_mysqlserver'])) {
|
||||||
$allowed_mysqlserver = json_encode(explode(",", $dbserver['allowed_mysqlserver']));
|
$allowed_mysqlserver = json_encode(explode(",", $dbserver['allowed_mysqlserver']));
|
||||||
Database::pexecute($upd_stmt, ['allowed_mysql_server' => $allowed_mysqlserver, 'customerid' => $dbserver['customerid']]);
|
Database::pexecute($upd_stmt,
|
||||||
|
['allowed_mysql_server' => $allowed_mysqlserver, 'customerid' => $dbserver['customerid']]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
@@ -140,7 +141,8 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
// none of the files existed
|
// none of the files existed
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
} else {
|
} else {
|
||||||
Update::lastStepStatus(1, 'manual commands needed', 'Please run the following commands manually:<br><pre>' . $del_list . '</pre>');
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,17 +184,16 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
Update::showUpdateStep("Updating email account password-hashes");
|
Update::showUpdateStep("Updating email account password-hashes");
|
||||||
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = REPLACE(`password`, '$1$', '{MD5-CRYPT}$1$') WHERE SUBSTRING(`password`, 1, 3) = '$1$'");
|
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$1$', '{MD5-CRYPT}$1$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$1$'");
|
||||||
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = REPLACE(`password`, '$5$', '{SHA256-CRYPT}$5$') WHERE SUBSTRING(`password`, 1, 3) = '$5$'");
|
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$5$', '{SHA256-CRYPT}$5$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$5$'");
|
||||||
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = REPLACE(`password`, '$6$', '{SHA512-CRYPT}$6$') WHERE SUBSTRING(`password`, 1, 3) = '$6$'");
|
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$6$', '{SHA512-CRYPT}$6$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$6$'");
|
||||||
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = REPLACE(`password`, '$2y$', '{BLF-CRYPT}$2y$') WHERE SUBSTRING(`password`, 1, 4) = '$2y$'");
|
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$2y$', '{BLF-CRYPT}$2y$') WHERE SUBSTRING(`password_enc`, 1, 4) = '$2y$'");
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
Froxlor::updateToVersion($update_to);
|
Froxlor::updateToVersion($update_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Froxlor::isDatabaseVersion('202112310')) {
|
if (Froxlor::isDatabaseVersion('202112310')) {
|
||||||
|
|
||||||
Update::showUpdateStep("Adjusting traffic tool settings");
|
Update::showUpdateStep("Adjusting traffic tool settings");
|
||||||
$traffic_tool = Settings::Get('system.awstats_enabled') == 1 ? 'awstats' : 'webalizer';
|
$traffic_tool = Settings::Get('system.awstats_enabled') == 1 ? 'awstats' : 'webalizer';
|
||||||
Settings::AddNew("system.traffictool", $traffic_tool);
|
Settings::AddNew("system.traffictool", $traffic_tool);
|
||||||
@@ -203,20 +204,31 @@ if (Froxlor::isDatabaseVersion('202112310')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Froxlor::isDatabaseVersion('202211030')) {
|
if (Froxlor::isDatabaseVersion('202211030')) {
|
||||||
|
|
||||||
Update::showUpdateStep("Creating backward compatibility for cronjob");
|
Update::showUpdateStep("Creating backward compatibility for cronjob");
|
||||||
|
$disabled = explode(',', ini_get('disable_functions'));
|
||||||
|
$exec_allowed = !in_array('exec', $disabled);
|
||||||
|
// check whether old files could be deleted in previous updates and if not,
|
||||||
|
// user should run cron to regenerate cron.d-file manually as he will run
|
||||||
|
// the other commands manually only after the update so this file would be deleted too
|
||||||
|
if ($exec_allowed) {
|
||||||
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
|
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
|
||||||
mkdir($complete_filedir, 0750, true);
|
mkdir($complete_filedir, 0750, true);
|
||||||
$newCronBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
|
$newCronBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
|
||||||
$compCron = <<<EOF
|
$compCron = <<<EOF
|
||||||
<?php
|
<?php
|
||||||
chmod($newCronBin, 0755);
|
chmod('$newCronBin', 0755);
|
||||||
// re-create cron.d configuration file
|
// re-create cron.d configuration file
|
||||||
exec('$newCronBin froxlor:cron -r 99');
|
exec('$newCronBin froxlor:cron -r 99');
|
||||||
exit;
|
exit;
|
||||||
EOF;
|
EOF;
|
||||||
file_put_contents($complete_filedir . '/froxlor_master_cronjob.php', $compCron);
|
file_put_contents($complete_filedir . '/froxlor_master_cronjob.php', $compCron);
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
||||||
|
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
||||||
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
||||||
|
}
|
||||||
|
|
||||||
Froxlor::updateToDbVersion('202212060');
|
Froxlor::updateToDbVersion('202212060');
|
||||||
}
|
}
|
||||||
@@ -245,3 +257,223 @@ if (Froxlor::isFroxlorVersion('2.0.1')) {
|
|||||||
Update::showUpdateStep("Updating from 2.0.1 to 2.0.2", false);
|
Update::showUpdateStep("Updating from 2.0.1 to 2.0.2", false);
|
||||||
Froxlor::updateToVersion('2.0.2');
|
Froxlor::updateToVersion('2.0.2');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.2')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.2 to 2.0.3", false);
|
||||||
|
Froxlor::updateToVersion('2.0.3');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.3')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.3 to 2.0.4", false);
|
||||||
|
|
||||||
|
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
|
||||||
|
// check if compat. cronjob still exists (most likely didn't run successfully b/c of error from former 2.0 release)
|
||||||
|
if (@file_exists($complete_filedir . '/froxlor_master_cronjob.php')) {
|
||||||
|
Update::showUpdateStep("Adjusting backward compatibility for cronjob");
|
||||||
|
$disabled = explode(',', ini_get('disable_functions'));
|
||||||
|
$exec_allowed = !in_array('exec', $disabled);
|
||||||
|
if ($exec_allowed) {
|
||||||
|
$newCronBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
|
||||||
|
$compCron = <<<EOF
|
||||||
|
<?php
|
||||||
|
chmod('$newCronBin', 0755);
|
||||||
|
// re-create cron.d configuration file
|
||||||
|
exec('$newCronBin froxlor:cron -r 99');
|
||||||
|
exit;
|
||||||
|
EOF;
|
||||||
|
file_put_contents($complete_filedir . '/froxlor_master_cronjob.php', $compCron);
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
||||||
|
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
||||||
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Froxlor::updateToVersion('2.0.4');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.4')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.4 to 2.0.5", false);
|
||||||
|
Froxlor::updateToVersion('2.0.5');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.5')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.5 to 2.0.6", false);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Updating possible missing email account password-hashes");
|
||||||
|
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$1$', '{MD5-CRYPT}$1$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$1$'");
|
||||||
|
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$5$', '{SHA256-CRYPT}$5$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$5$'");
|
||||||
|
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$6$', '{SHA512-CRYPT}$6$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$6$'");
|
||||||
|
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$2y$', '{BLF-CRYPT}$2y$') WHERE SUBSTRING(`password_enc`, 1, 4) = '$2y$'");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToVersion('2.0.6');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.6')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.6 to 2.0.7", false);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Correcting allowed_mysqlserver for customers");
|
||||||
|
Database::query("UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `allowed_mysqlserver` = '[0]' WHERE `allowed_mysqlserver` = ''");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToVersion('2.0.7');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202212060')) {
|
||||||
|
Update::showUpdateStep("Validating acme.sh challenge path");
|
||||||
|
$acmesh_challenge_dir = Settings::Get('system.letsencryptchallengepath');
|
||||||
|
$system_letsencryptchallengepath_upd = isset($_POST['system_letsencryptchallengepath_upd']) ? $_POST['system_letsencryptchallengepath_upd'] : $acmesh_challenge_dir;
|
||||||
|
if ($acmesh_challenge_dir != $system_letsencryptchallengepath_upd) {
|
||||||
|
Settings::Set('system.letsencryptchallengepath', $system_letsencryptchallengepath_upd);
|
||||||
|
if ((int)Settings::Get('system.leenabled') == 1) {
|
||||||
|
// create JSON string for --apply
|
||||||
|
$dist = Settings::Get('system.distribution');
|
||||||
|
$webserver = Settings::Get('system.webserver');
|
||||||
|
if ($webserver == 'apache2') {
|
||||||
|
$webserver = 'apache22';
|
||||||
|
if (Settings::Get('system.apache24')) {
|
||||||
|
$webserver = 'apache24';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$apply_json = '{"http":"' . $webserver . '","dns":"x","smtp":"x","mail":"x","ftp":"x","distro":"' . $dist . '","system":[]}';
|
||||||
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
"Please reconfigure webserver service using <pre>bin/froxlor-cli froxlor:config-services --apply='" . $apply_json . "'</pre>" .
|
||||||
|
'<br>or adjust the path manually in <pre>' . Settings::Get('system.letsencryptacmeconf') . '</pre>' .
|
||||||
|
'<br><br>In case you already have certificates issued, run the following command to validate and correct the webroot used for renewal:<br>' .
|
||||||
|
'<pre>bin/froxlor-cli froxlor:validate-acme-webroot</pre><br>'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202301120');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.7')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.7 to 2.0.8", false);
|
||||||
|
|
||||||
|
// adjust file-logging to be set to froxlor/logs/
|
||||||
|
$logtypes = explode(',', Settings::Get('logger.logtypes'));
|
||||||
|
if (in_array('file', $logtypes)) {
|
||||||
|
Update::showUpdateStep("Adjusting froxlor logfile for system-logging to be stored in logs/froxlor.log");
|
||||||
|
Settings::Set('logger.logfile', 'froxlor.log');
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Froxlor::updateToVersion('2.0.8');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202301120')) {
|
||||||
|
Update::showUpdateStep("Adding new setting for DNS resolver when using Let's Encrypt");
|
||||||
|
$system_le_domain_dnscheck_resolver = isset($_POST['system_le_domain_dnscheck_resolver']) ? $_POST['system_le_domain_dnscheck_resolver'] : '1.1.1.1';
|
||||||
|
Settings::AddNew("system.le_domain_dnscheck_resolver", $system_le_domain_dnscheck_resolver);
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202301180');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.8')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.8 to 2.0.9", false);
|
||||||
|
Froxlor::updateToVersion('2.0.9');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.9')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.9 to 2.0.10", false);
|
||||||
|
Froxlor::updateToVersion('2.0.10');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202301180')) {
|
||||||
|
Update::showUpdateStep("Adding new setting for 'Allow API access' default value for new customers");
|
||||||
|
Settings::AddNew("api.customer_default", "1");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202302030');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.10')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.10 to 2.0.11", false);
|
||||||
|
Froxlor::updateToVersion('2.0.11');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.11')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.11 to 2.0.12", false);
|
||||||
|
Froxlor::updateToVersion('2.0.12');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.12')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.12 to 2.0.13", false);
|
||||||
|
Froxlor::updateToVersion('2.0.13');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202302030')) {
|
||||||
|
Update::showUpdateStep("Correcting language mapping of templates created pre 2.0.x");
|
||||||
|
// languages from 0.10.x
|
||||||
|
$language_mapping_comp = [
|
||||||
|
'de' => 'Deutsch',
|
||||||
|
'en' => 'English',
|
||||||
|
'fr' => 'Français',
|
||||||
|
'pt' => 'Português',
|
||||||
|
'it' => 'Italiano',
|
||||||
|
'nl' => 'Nederlands',
|
||||||
|
'se' => 'Svenska',
|
||||||
|
'cz' => 'Česká republika'
|
||||||
|
];
|
||||||
|
$upd_tpl_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET `language` = :iso WHERE `language` = :lng");
|
||||||
|
foreach ($language_mapping_comp as $iso => $lang) {
|
||||||
|
Database::pexecute($upd_tpl_stmt, ['iso' => $iso, 'lng' => $lang]);
|
||||||
|
}
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Enhancing ssl data table");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` CHANGE `expirationdate` `validtodate` datetime DEFAULT NULL;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` ADD `validfromdate` datetime DEFAULT NULL AFTER `ssl_fullchain_file`;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` ADD `issuer` varchar(255) NOT NULL default '' AFTER `validtodate`;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Filling new ssl data fields with existing certificate data");
|
||||||
|
$crt_upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` SET `validfromdate` = :validfromdate, `issuer` = :issuer WHERE `id` = :id");
|
||||||
|
$crt_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`");
|
||||||
|
Database::pexecute($crt_stmt);
|
||||||
|
while ($cert = $crt_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$cert_content = openssl_x509_parse($cert['ssl_cert_file']);
|
||||||
|
if (is_array($cert_content)) {
|
||||||
|
$validfromdate = empty($cert_content['validFrom_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validFrom_time_t']);
|
||||||
|
$issuer = $cert_content['issuer']['O'] ?? "";
|
||||||
|
Database::pexecute($crt_upd_stmt, ['validfromdate' => $validfromdate, 'issuer' => $issuer, 'id' => $cert['id']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear possible user customized columns
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_USERCOLUMNS . "` WHERE `section` = 'sslcertificates_list'");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202303150');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.13')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.13 to 2.0.14", false);
|
||||||
|
Froxlor::updateToVersion('2.0.14');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.14')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.14 to 2.0.15", false);
|
||||||
|
Froxlor::updateToVersion('2.0.15');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202303150')) {
|
||||||
|
Update::showUpdateStep("Adding new request rate limit settings");
|
||||||
|
Settings::AddNew("system.req_limit_per_interval", "60");
|
||||||
|
Settings::AddNew("system.req_limit_interval", "60");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202304260');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.15')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.15 to 2.0.16", false);
|
||||||
|
Froxlor::updateToVersion('2.0.16');
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,9 +34,14 @@ $return = [];
|
|||||||
if (Update::versionInUpdate($current_db_version, '202004140')) {
|
if (Update::versionInUpdate($current_db_version, '202004140')) {
|
||||||
$has_preconfig = true;
|
$has_preconfig = true;
|
||||||
$description = 'Froxlor can now optionally validate the dns entries of domains that request Lets Encrypt certificates to reduce dns-related problems (e.g. freshly registered domain or updated a-record).';
|
$description = 'Froxlor can now optionally validate the dns entries of domains that request Lets Encrypt certificates to reduce dns-related problems (e.g. freshly registered domain or updated a-record).';
|
||||||
$return['system_le_domain_dnscheck_note'] = ['type' => 'infotext', 'value' => $description];
|
|
||||||
$question = '<strong>Validate DNS of domains when using Lets Encrypt ';
|
$question = '<strong>Validate DNS of domains when using Lets Encrypt ';
|
||||||
$return['system_le_domain_dnscheck'] = ['type' => 'checkbox', 'value' => 1, 'checked' => 1, 'label' => $question];
|
$return['system_le_domain_dnscheck'] = [
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'value' => 1,
|
||||||
|
'checked' => 1,
|
||||||
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$preconfig['fields'] = $return;
|
$preconfig['fields'] = $return;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ use Froxlor\Froxlor;
|
|||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\Config\ConfigParser;
|
use Froxlor\Config\ConfigParser;
|
||||||
use Froxlor\Install\Update;
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
|
||||||
$preconfig = [
|
$preconfig = [
|
||||||
'title' => '2.x updates',
|
'title' => '2.x updates',
|
||||||
@@ -36,7 +37,6 @@ $return = [];
|
|||||||
|
|
||||||
if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
||||||
$description = 'We have rearranged the settings and split them into basic and advanced categories. This makes it easier for users who do not need all the detailed or very specific settings and options and gives a better overview of the basic/mostly used settings.';
|
$description = 'We have rearranged the settings and split them into basic and advanced categories. This makes it easier for users who do not need all the detailed or very specific settings and options and gives a better overview of the basic/mostly used settings.';
|
||||||
$return['panel_settings_mode_note'] = ['type' => 'infotext', 'value' => $description];
|
|
||||||
$question = '<strong>Chose settings mode (you can change that at any time)</strong>';
|
$question = '<strong>Chose settings mode (you can change that at any time)</strong>';
|
||||||
$return['panel_settings_mode'] = [
|
$return['panel_settings_mode'] = [
|
||||||
'type' => 'select',
|
'type' => 'select',
|
||||||
@@ -45,11 +45,11 @@ if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
|||||||
1 => 'Advanced'
|
1 => 'Advanced'
|
||||||
],
|
],
|
||||||
'selected' => 1,
|
'selected' => 1,
|
||||||
'label' => $question
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description
|
||||||
];
|
];
|
||||||
|
|
||||||
$description = 'The configuration page now can preselect a distribution, please select your current distribution';
|
$description = 'The configuration page now can preselect a distribution, please select your current distribution';
|
||||||
$return['system_distribution_note'] = ['type' => 'infotext', 'value' => $description];
|
|
||||||
$question = '<strong>Select distribution</strong>';
|
$question = '<strong>Select distribution</strong>';
|
||||||
$config_dir = FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/lib/configfiles/');
|
$config_dir = FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/lib/configfiles/');
|
||||||
// show list of available distro's
|
// show list of available distro's
|
||||||
@@ -68,9 +68,44 @@ if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
|||||||
'type' => 'select',
|
'type' => 'select',
|
||||||
'select_var' => $distributions_select,
|
'select_var' => $distributions_select,
|
||||||
'selected' => '',
|
'selected' => '',
|
||||||
'label' => $question
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Update::versionInUpdate($current_db_version, '202301120')) {
|
||||||
|
$acmesh_challenge_dir = rtrim(FileDir::makeCorrectDir(Settings::Get('system.letsencryptchallengepath')), "/");
|
||||||
|
$recommended = rtrim(FileDir::makeCorrectDir(Froxlor::getInstallDir()), "/");
|
||||||
|
if ((int) Settings::Get('system.leenabled') == 1 && $acmesh_challenge_dir != $recommended) {
|
||||||
|
$has_preconfig = true;
|
||||||
|
$description = 'ACME challenge docroot from settings differs from the current installation directory.';
|
||||||
|
$question = '<strong>Validate Let\'s Encrypt challenge path (recommended value: ' . $recommended . ')</strong>';
|
||||||
|
$return['system_letsencryptchallengepath_upd'] = [
|
||||||
|
'type' => 'text',
|
||||||
|
'value' => $recommended,
|
||||||
|
'placeholder' => $acmesh_challenge_dir,
|
||||||
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description,
|
||||||
|
'mandatory' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Update::versionInUpdate($current_db_version, '202301180')) {
|
||||||
|
if ((int) Settings::Get('system.leenabled') == 1) {
|
||||||
|
$has_preconfig = true;
|
||||||
|
$description = 'Froxlor now supports to set an external DNS resolver for the Let\'s Encrypt pre-check.';
|
||||||
|
$question = '<strong>Specify a DNS resolver IP (recommended value: 1.1.1.1 or similar)</strong>';
|
||||||
|
$return['system_le_domain_dnscheck_resolver'] = [
|
||||||
|
'type' => 'text',
|
||||||
|
'pattern' => '^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$|^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$|^\s*$',
|
||||||
|
'value' => '1.1.1.1',
|
||||||
|
'placeholder' => '1.1.1.1',
|
||||||
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$preconfig['fields'] = $return;
|
$preconfig['fields'] = $return;
|
||||||
return $preconfig;
|
return $preconfig;
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ class Ajax
|
|||||||
$content = preg_replace("/[\r\n]+/", " ", strip_tags($item->description));
|
$content = preg_replace("/[\r\n]+/", " ", strip_tags($item->description));
|
||||||
$content = substr($content, 0, 150) . "...";
|
$content = substr($content, 0, 150) . "...";
|
||||||
|
|
||||||
$items .= UI::twig()->render($this->theme . '/user/newsfeeditem.html.twig', [
|
$items .= UI::twig()->render(UI::validateThemeTemplate('/user/newsfeeditem.html.twig', $this->theme), [
|
||||||
'link' => $link,
|
'link' => $link,
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'date' => $date,
|
'date' => $date,
|
||||||
@@ -201,7 +201,7 @@ class Ajax
|
|||||||
$result['last_update_check'] = $uc_data['ts'];
|
$result['last_update_check'] = $uc_data['ts'];
|
||||||
$result['channel'] = Settings::Get('system.update_channel');
|
$result['channel'] = Settings::Get('system.update_channel');
|
||||||
|
|
||||||
$result_rendered = UI::twig()->render($this->theme . '/misc/version_top.html.twig', $result);
|
$result_rendered = UI::twig()->render(UI::validateThemeTemplate('/misc/version_top.html.twig', $this->theme), $result);
|
||||||
return $this->jsonResponse($result_rendered);
|
return $this->jsonResponse($result_rendered);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// don't display anything if just not allowed due to permissions
|
// don't display anything if just not allowed due to permissions
|
||||||
@@ -237,11 +237,11 @@ class Ajax
|
|||||||
private function updateTablelisting()
|
private function updateTablelisting()
|
||||||
{
|
{
|
||||||
$columns = [];
|
$columns = [];
|
||||||
foreach ((Request::any('columns') ?? []) as $value) {
|
foreach ((Request::post('columns') ?? []) as $value) {
|
||||||
$columns[] = $value;
|
$columns[] = $value;
|
||||||
}
|
}
|
||||||
if (!empty($columns)) {
|
if (!empty($columns)) {
|
||||||
Listing::storeColumnListingForUser([Request::any('listing') => $columns]);
|
$columns = Listing::storeColumnListingForUser([Request::get('listing') => $columns]);
|
||||||
return $this->jsonResponse($columns);
|
return $this->jsonResponse($columns);
|
||||||
}
|
}
|
||||||
return $this->errorResponse('At least one column must be selected', 406);
|
return $this->errorResponse('At least one column must be selected', 406);
|
||||||
@@ -249,7 +249,7 @@ class Ajax
|
|||||||
|
|
||||||
private function resetTablelisting()
|
private function resetTablelisting()
|
||||||
{
|
{
|
||||||
Listing::deleteColumnListingForUser([Request::any('listing') => []]);
|
Listing::deleteColumnListingForUser([Request::get('listing') => []]);
|
||||||
return $this->jsonResponse([]);
|
return $this->jsonResponse([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace Froxlor\Ajax;
|
|||||||
use Froxlor\Api\Commands\Admins;
|
use Froxlor\Api\Commands\Admins;
|
||||||
use Froxlor\Api\Commands\Customers;
|
use Froxlor\Api\Commands\Customers;
|
||||||
use Froxlor\Api\Commands\Domains;
|
use Froxlor\Api\Commands\Domains;
|
||||||
|
use Froxlor\Api\Commands\EmailDomains;
|
||||||
use Froxlor\Api\Commands\Emails;
|
use Froxlor\Api\Commands\Emails;
|
||||||
use Froxlor\Api\Commands\FpmDaemons;
|
use Froxlor\Api\Commands\FpmDaemons;
|
||||||
use Froxlor\Api\Commands\Ftps;
|
use Froxlor\Api\Commands\Ftps;
|
||||||
@@ -267,7 +268,20 @@ class GlobalSearch
|
|||||||
'result_format' => [
|
'result_format' => [
|
||||||
'title' => ['self', 'getFieldFromResult'],
|
'title' => ['self', 'getFieldFromResult'],
|
||||||
'title_args' => 'email',
|
'title_args' => 'email',
|
||||||
'href' => 'customer_email.php?page=emails&searchfield=m.email&searchtext='
|
'href' => 'customer_email.php?page=email_domain&domainid={domainid}&searchfield=m.email&searchtext='
|
||||||
|
]
|
||||||
|
],
|
||||||
|
// email-domains
|
||||||
|
'email_domains' => [
|
||||||
|
'class' => EmailDomains::class,
|
||||||
|
'searchfields' => [
|
||||||
|
'd.domain',
|
||||||
|
],
|
||||||
|
'result_key' => 'domain',
|
||||||
|
'result_format' => [
|
||||||
|
'title' => ['self', 'getFieldFromResult'],
|
||||||
|
'title_args' => 'domain',
|
||||||
|
'href' => 'customer_email.php?page=emails&searchfield=d.domain&searchtext='
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
// databases
|
// databases
|
||||||
@@ -326,6 +340,14 @@ class GlobalSearch
|
|||||||
if (!isset($result[$entity])) {
|
if (!isset($result[$entity])) {
|
||||||
$result[$entity] = [];
|
$result[$entity] = [];
|
||||||
}
|
}
|
||||||
|
// replacer from result in href
|
||||||
|
$href_replacer = [];
|
||||||
|
if (preg_match_all('/\{([a-z]+)\}/', $edata['result_format']['href'], $href_replacer) !== false) {
|
||||||
|
foreach ($href_replacer[1] as $href_field) {
|
||||||
|
$href_field_value = self::getFieldFromResult($cresult, $href_field);
|
||||||
|
$edata['result_format']['href'] = str_replace('{'.$href_field.'}', $href_field_value, $edata['result_format']['href']);
|
||||||
|
}
|
||||||
|
}
|
||||||
$result[$entity][] = [
|
$result[$entity][] = [
|
||||||
'title' => call_user_func($edata['result_format']['title'], $cresult, ($edata['result_format']['title_args'] ?? null)),
|
'title' => call_user_func($edata['result_format']['title'], $cresult, ($edata['result_format']['title_args'] ?? null)),
|
||||||
'href' => $edata['result_format']['href'] . $cresult[$edata['result_key']]
|
'href' => $edata['result_format']['href'] . $cresult[$edata['result_key']]
|
||||||
@@ -335,7 +357,7 @@ class GlobalSearch
|
|||||||
}
|
}
|
||||||
} // foreach entity
|
} // foreach entity
|
||||||
|
|
||||||
} // foreach splitted search-term
|
} // foreach split search-term
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
namespace Froxlor\Api;
|
namespace Froxlor\Api;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Froxlor\Http\RateLimiter;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use voku\helper\AntiXSS;
|
use voku\helper\AntiXSS;
|
||||||
|
|
||||||
@@ -52,6 +53,8 @@ class Api
|
|||||||
if (Settings::Get('api.enabled') != 1) {
|
if (Settings::Get('api.enabled') != 1) {
|
||||||
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
|
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RateLimiter::run();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,6 +120,6 @@ class Api
|
|||||||
|
|
||||||
private function stripcslashesDeep($value)
|
private function stripcslashesDeep($value)
|
||||||
{
|
{
|
||||||
return is_array($value) ? array_map([$this, 'stripcslashesDeep'], $value) : stripcslashes($value);
|
return is_array($value) ? array_map([$this, 'stripcslashesDeep'], $value) : (!empty($value) ? stripcslashes($value) : $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,7 +127,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
$do_verify = true;
|
$do_verify = true;
|
||||||
$expirationdate = null;
|
$validtodate = null;
|
||||||
|
$validtodate = null;
|
||||||
|
$issuer = "";
|
||||||
// no cert-file given -> forget everything
|
// no cert-file given -> forget everything
|
||||||
if ($ssl_cert_file == '') {
|
if ($ssl_cert_file == '') {
|
||||||
$ssl_key_file = '';
|
$ssl_key_file = '';
|
||||||
@@ -168,7 +170,10 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
} else {
|
} else {
|
||||||
Response::standardError('sslcertificateinvalidcert', '', true);
|
Response::standardError('sslcertificateinvalidcert', '', true);
|
||||||
}
|
}
|
||||||
$expirationdate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']);
|
// get data from certificate to store in the table
|
||||||
|
$validfromdate = empty($cert_content['validFrom_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validFrom_time_t']);
|
||||||
|
$validtodate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']);
|
||||||
|
$issuer = $cert_content['issuer']['O'] ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add/Update database entry
|
// Add/Update database entry
|
||||||
@@ -183,7 +188,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
`ssl_key_file` = :ssl_key_file,
|
`ssl_key_file` = :ssl_key_file,
|
||||||
`ssl_ca_file` = :ssl_ca_file,
|
`ssl_ca_file` = :ssl_ca_file,
|
||||||
`ssl_cert_chainfile` = :ssl_cert_chainfile,
|
`ssl_cert_chainfile` = :ssl_cert_chainfile,
|
||||||
`expirationdate` = :expirationdate
|
`validfromdate` = :validfromdate,
|
||||||
|
`validtodate` = :validtodate,
|
||||||
|
`issuer` = :issuer
|
||||||
" . $qrywhere . " `domainid`= :domainid
|
" . $qrywhere . " `domainid`= :domainid
|
||||||
");
|
");
|
||||||
$params = [
|
$params = [
|
||||||
@@ -191,7 +198,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
"ssl_key_file" => $ssl_key_file,
|
"ssl_key_file" => $ssl_key_file,
|
||||||
"ssl_ca_file" => $ssl_ca_file,
|
"ssl_ca_file" => $ssl_ca_file,
|
||||||
"ssl_cert_chainfile" => $ssl_cert_chainfile,
|
"ssl_cert_chainfile" => $ssl_cert_chainfile,
|
||||||
"expirationdate" => $expirationdate,
|
"validfromdate" => $validfromdate,
|
||||||
|
"validtodate" => $validtodate,
|
||||||
|
"issuer" => $issuer,
|
||||||
"domainid" => $domainid
|
"domainid" => $domainid
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
@@ -299,16 +308,12 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set data from certificate
|
// Set data from certificate
|
||||||
|
$cert['isvalid'] = false;
|
||||||
|
$cert['san'] = null;
|
||||||
$cert_data = openssl_x509_parse($cert['ssl_cert_file']);
|
$cert_data = openssl_x509_parse($cert['ssl_cert_file']);
|
||||||
if ($cert_data) {
|
if ($cert_data) {
|
||||||
$cert['validfromdate'] = date('Y-m-d H:i:s', $cert_data['validFrom_time_t']);
|
|
||||||
$cert['validtodate'] = date('Y-m-d H:i:s', $cert_data['validTo_time_t']);
|
|
||||||
$cert['isvalid'] = (bool)$cert_data['validTo_time_t'] > time();
|
$cert['isvalid'] = (bool)$cert_data['validTo_time_t'] > time();
|
||||||
$cert['issuer'] = $cert_data['issuer']['O'] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set subject alt names from certificate
|
// Set subject alt names from certificate
|
||||||
$cert['san'] = null;
|
|
||||||
if (isset($cert_data['extensions']['subjectAltName']) && !empty($cert_data['extensions']['subjectAltName'])) {
|
if (isset($cert_data['extensions']['subjectAltName']) && !empty($cert_data['extensions']['subjectAltName'])) {
|
||||||
$SANs = explode(",", $cert_data['extensions']['subjectAltName']);
|
$SANs = explode(",", $cert_data['extensions']['subjectAltName']);
|
||||||
$SANs = array_map('trim', $SANs);
|
$SANs = array_map('trim', $SANs);
|
||||||
@@ -319,7 +324,7 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$result[] = $cert;
|
$result[] = $cert;
|
||||||
}
|
}
|
||||||
return $this->response([
|
return $this->response([
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ use Froxlor\Cron\TaskId;
|
|||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use PDO;
|
use PDO;
|
||||||
|
|
||||||
@@ -41,6 +42,14 @@ use PDO;
|
|||||||
class Cronjobs extends ApiCommand implements ResourceEntity
|
class Cronjobs extends ApiCommand implements ResourceEntity
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private array $allowed_intervals = [
|
||||||
|
'MINUTE',
|
||||||
|
'HOUR',
|
||||||
|
'DAY',
|
||||||
|
'WEEK',
|
||||||
|
'MONTH'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You cannot add new cronjobs yet.
|
* You cannot add new cronjobs yet.
|
||||||
*/
|
*/
|
||||||
@@ -118,6 +127,10 @@ class Cronjobs extends ApiCommand implements ResourceEntity
|
|||||||
$interval_value = Validate::validate($interval_value, 'interval_value', '/^([0-9]+)$/Di', 'stringisempty', [], true);
|
$interval_value = Validate::validate($interval_value, 'interval_value', '/^([0-9]+)$/Di', 'stringisempty', [], true);
|
||||||
$interval_interval = Validate::validate($interval_interval, 'interval_interval', '', '', [], true);
|
$interval_interval = Validate::validate($interval_interval, 'interval_interval', '', '', [], true);
|
||||||
|
|
||||||
|
if (!in_array(strtoupper($interval_interval), $this->allowed_intervals)) {
|
||||||
|
Response::standardError('invalidcronjobintervalvalue', implode(", ", $this->allowed_intervals), true);
|
||||||
|
}
|
||||||
|
|
||||||
// put together interval value
|
// put together interval value
|
||||||
$interval = $interval_value . ' ' . strtoupper($interval_interval);
|
$interval = $interval_value . ' ' . strtoupper($interval_interval);
|
||||||
|
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
$fax = $this->getParam('fax', true, '');
|
$fax = $this->getParam('fax', true, '');
|
||||||
$customernumber = $this->getParam('customernumber', true, '');
|
$customernumber = $this->getParam('customernumber', true, '');
|
||||||
$def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage'));
|
$def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage'));
|
||||||
$api_allowed = $this->getBoolParam('api_allowed', true, Settings::Get('api.enabled'));
|
$api_allowed = $this->getBoolParam('api_allowed', true, (Settings::Get('api.enabled') && Settings::Get('api.customer_default')));
|
||||||
$gender = (int)$this->getParam('gender', true, 0);
|
$gender = (int)$this->getParam('gender', true, 0);
|
||||||
$custom_notes = $this->getParam('custom_notes', true, '');
|
$custom_notes = $this->getParam('custom_notes', true, '');
|
||||||
$custom_notes_show = $this->getBoolParam('custom_notes_show', true, 0);
|
$custom_notes_show = $this->getBoolParam('custom_notes_show', true, 0);
|
||||||
|
|||||||
@@ -157,16 +157,15 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
* this functions validates a given value as ErrorDocument
|
* this functions validates a given value as ErrorDocument
|
||||||
* refs #267
|
* refs #267
|
||||||
*
|
*
|
||||||
* @param
|
* @param string $errdoc
|
||||||
* string error-document-string
|
|
||||||
* @param bool $throw_exception
|
* @param bool $throw_exception
|
||||||
*
|
*
|
||||||
* @return string error-document-string
|
* @return string error-document-string
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private function correctErrorDocument($errdoc = null, $throw_exception = false)
|
private function correctErrorDocument(string $errdoc, $throw_exception = false)
|
||||||
{
|
{
|
||||||
if ($errdoc !== null && $errdoc != '') {
|
if (trim($errdoc) != '') {
|
||||||
// not a URL
|
// not a URL
|
||||||
if ((strtoupper(substr($errdoc, 0, 5)) != 'HTTP:' && strtoupper(substr($errdoc, 0, 6)) != 'HTTPS:') || !Validate::validateUrl($errdoc)) {
|
if ((strtoupper(substr($errdoc, 0, 5)) != 'HTTP:' && strtoupper(substr($errdoc, 0, 6)) != 'HTTPS:') || !Validate::validateUrl($errdoc)) {
|
||||||
// a file
|
// a file
|
||||||
@@ -176,14 +175,14 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
if (!substr($errdoc, 0, 1) == '/') {
|
if (!substr($errdoc, 0, 1) == '/') {
|
||||||
$errdoc = '/' . $errdoc;
|
$errdoc = '/' . $errdoc;
|
||||||
}
|
}
|
||||||
} else {
|
} elseif (preg_match('/^"([^\r\n\t\f\0"]+)"$/', $errdoc)) {
|
||||||
// a string (check for ending ")
|
// a string (check for ending ")
|
||||||
// string won't work for lighty
|
// string won't work for lighty
|
||||||
if (Settings::Get('system.webserver') == 'lighttpd') {
|
if (Settings::Get('system.webserver') == 'lighttpd') {
|
||||||
Response::standardError('stringerrordocumentnotvalidforlighty', '', $throw_exception);
|
Response::standardError('stringerrordocumentnotvalidforlighty', '', $throw_exception);
|
||||||
} elseif (substr($errdoc, -1) != '"') {
|
|
||||||
$errdoc .= '"';
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Response::standardError('invaliderrordocumentvalue', '', $throw_exception);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Settings::Get('system.webserver') == 'lighttpd') {
|
if (Settings::Get('system.webserver') == 'lighttpd') {
|
||||||
@@ -191,7 +190,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $errdoc;
|
return trim($errdoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
|
$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);
|
||||||
Validate::validate($password, 'password', '', '', [], true);
|
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||||
|
$password = Crypt::validatePassword($password, true);
|
||||||
|
|
||||||
// check for duplicate usernames for the path
|
// check for duplicate usernames for the path
|
||||||
$username_path_check_stmt = Database::prepare("
|
$username_path_check_stmt = Database::prepare("
|
||||||
@@ -244,7 +245,8 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validation
|
// validation
|
||||||
$authname = Validate::validate($authname, 'directory_authname', '/^[a-zA-Z0-9][a-zA-Z0-9\-_ ]+\$?$/', '', [], true);
|
$authname = Validate::validate($authname, 'directory_authname', '/^[a-zA-Z0-9][a-zA-Z0-9\-_ ]+\$?$/', '', [], true);
|
||||||
Validate::validate($password, 'password', '', '', [], true);
|
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||||
|
$password = Crypt::validatePassword($password, true);
|
||||||
|
|
||||||
$upd_query = "";
|
$upd_query = "";
|
||||||
$upd_params = [
|
$upd_params = [
|
||||||
|
|||||||
@@ -225,6 +225,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, whether php is enabled for this domain, default 0 (false)
|
* optional, whether php is enabled for this domain, default 0 (false)
|
||||||
* @param bool $openbasedir
|
* @param bool $openbasedir
|
||||||
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
||||||
|
* @param int $openbasedir_path
|
||||||
|
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
||||||
* @param int $mod_fcgid_starter
|
* @param int $mod_fcgid_starter
|
||||||
@@ -312,6 +314,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$documentroot = $this->getParam('documentroot', true, '');
|
$documentroot = $this->getParam('documentroot', true, '');
|
||||||
$phpenabled = $this->getBoolParam('phpenabled', true, 0);
|
$phpenabled = $this->getBoolParam('phpenabled', true, 0);
|
||||||
$openbasedir = $this->getBoolParam('openbasedir', true, 0);
|
$openbasedir = $this->getBoolParam('openbasedir', true, 0);
|
||||||
|
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, 1);
|
$phpsettingid = $this->getParam('phpsettingid', true, 1);
|
||||||
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, -1);
|
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, -1);
|
||||||
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
|
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
|
||||||
@@ -404,20 +407,25 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$documentroot = $_documentroot;
|
$documentroot = $_documentroot;
|
||||||
}
|
}
|
||||||
|
|
||||||
$registration_date = Validate::validate($registration_date, 'registration_date', Validate::REGEX_YYYY_MM_DD, '', [
|
if (!is_null($registration_date)) {
|
||||||
|
$registration_date = Validate::validate($registration_date, 'registration_date',
|
||||||
|
Validate::REGEX_YYYY_MM_DD, '', [
|
||||||
'0000-00-00',
|
'0000-00-00',
|
||||||
'0',
|
'0',
|
||||||
''
|
''
|
||||||
], true);
|
], true);
|
||||||
|
}
|
||||||
if ($registration_date == '0000-00-00' || empty($registration_date)) {
|
if ($registration_date == '0000-00-00' || empty($registration_date)) {
|
||||||
$registration_date = null;
|
$registration_date = null;
|
||||||
}
|
}
|
||||||
|
if (!is_null($termination_date)) {
|
||||||
$termination_date = Validate::validate($termination_date, 'termination_date', Validate::REGEX_YYYY_MM_DD, '', [
|
$termination_date = Validate::validate($termination_date, 'termination_date',
|
||||||
|
Validate::REGEX_YYYY_MM_DD, '', [
|
||||||
'0000-00-00',
|
'0000-00-00',
|
||||||
'0',
|
'0',
|
||||||
''
|
''
|
||||||
], true);
|
], true);
|
||||||
|
}
|
||||||
if ($termination_date == '0000-00-00' || empty($termination_date)) {
|
if ($termination_date == '0000-00-00' || empty($termination_date)) {
|
||||||
$termination_date = null;
|
$termination_date = null;
|
||||||
}
|
}
|
||||||
@@ -525,6 +533,10 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$mod_fcgid_maxrequests = '-1';
|
$mod_fcgid_maxrequests = '-1';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
|
||||||
|
$openbasedir_path = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check non-ssl IP
|
// check non-ssl IP
|
||||||
$ipandports = $this->validateIpAddresses($p_ipandports);
|
$ipandports = $this->validateIpAddresses($p_ipandports);
|
||||||
// check ssl IP
|
// check ssl IP
|
||||||
@@ -559,7 +571,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
||||||
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
||||||
$domain_ips = PhpHelper::gethostbynamel6($domain);
|
$domain_ips = PhpHelper::gethostbynamel6($domain, true, Settings::Get('system.le_domain_dnscheck_resolver'));
|
||||||
$selected_ips = $this->getIpsFromIdArray($ssl_ipandports);
|
$selected_ips = $this->getIpsFromIdArray($ssl_ipandports);
|
||||||
if ($domain_ips == false || count(array_intersect($selected_ips, $domain_ips)) <= 0) {
|
if ($domain_ips == false || count(array_intersect($selected_ips, $domain_ips)) <= 0) {
|
||||||
Response::standardError('invaliddnsforletsencrypt', '', true);
|
Response::standardError('invaliddnsforletsencrypt', '', true);
|
||||||
@@ -696,6 +708,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
'caneditdomain' => $caneditdomain,
|
'caneditdomain' => $caneditdomain,
|
||||||
'phpenabled' => $phpenabled,
|
'phpenabled' => $phpenabled,
|
||||||
'openbasedir' => $openbasedir,
|
'openbasedir' => $openbasedir,
|
||||||
|
'openbasedir_path' => $openbasedir_path,
|
||||||
'speciallogfile' => $speciallogfile,
|
'speciallogfile' => $speciallogfile,
|
||||||
'specialsettings' => $specialsettings,
|
'specialsettings' => $specialsettings,
|
||||||
'ssl_specialsettings' => $ssl_specialsettings,
|
'ssl_specialsettings' => $ssl_specialsettings,
|
||||||
@@ -749,6 +762,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`caneditdomain` = :caneditdomain,
|
`caneditdomain` = :caneditdomain,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`speciallogfile` = :speciallogfile,
|
`speciallogfile` = :speciallogfile,
|
||||||
`specialsettings` = :specialsettings,
|
`specialsettings` = :specialsettings,
|
||||||
`ssl_specialsettings` = :ssl_specialsettings,
|
`ssl_specialsettings` = :ssl_specialsettings,
|
||||||
@@ -1096,6 +1110,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* from setting system.apply_phpconfigs_default
|
* from setting system.apply_phpconfigs_default
|
||||||
* @param bool $openbasedir
|
* @param bool $openbasedir
|
||||||
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
||||||
|
* @param int $openbasedir_path
|
||||||
|
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
||||||
* @param int $mod_fcgid_starter
|
* @param int $mod_fcgid_starter
|
||||||
@@ -1193,6 +1209,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$phpenabled = $this->getBoolParam('phpenabled', true, $result['phpenabled']);
|
$phpenabled = $this->getBoolParam('phpenabled', true, $result['phpenabled']);
|
||||||
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, Settings::Get('system.apply_phpconfigs_default'));
|
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, Settings::Get('system.apply_phpconfigs_default'));
|
||||||
$openbasedir = $this->getBoolParam('openbasedir', true, $result['openbasedir']);
|
$openbasedir = $this->getBoolParam('openbasedir', true, $result['openbasedir']);
|
||||||
|
$openbasedir_path = $this->getParam('openbasedir_path', true, $result['openbasedir_path']);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
||||||
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, $result['mod_fcgid_starter']);
|
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, $result['mod_fcgid_starter']);
|
||||||
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, $result['mod_fcgid_maxrequests']);
|
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, $result['mod_fcgid_maxrequests']);
|
||||||
@@ -1322,19 +1339,25 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$adminid = $result['adminid'];
|
$adminid = $result['adminid'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$registration_date = Validate::validate($registration_date, 'registration_date', Validate::REGEX_YYYY_MM_DD, '', [
|
if (!is_null($registration_date)) {
|
||||||
|
$registration_date = Validate::validate($registration_date, 'registration_date',
|
||||||
|
Validate::REGEX_YYYY_MM_DD, '', [
|
||||||
'0000-00-00',
|
'0000-00-00',
|
||||||
'0',
|
'0',
|
||||||
''
|
''
|
||||||
], true);
|
], true);
|
||||||
|
}
|
||||||
if ($registration_date == '0000-00-00' || empty($registration_date)) {
|
if ($registration_date == '0000-00-00' || empty($registration_date)) {
|
||||||
$registration_date = null;
|
$registration_date = null;
|
||||||
}
|
}
|
||||||
$termination_date = Validate::validate($termination_date, 'termination_date', Validate::REGEX_YYYY_MM_DD, '', [
|
if (!is_null($termination_date)) {
|
||||||
|
$termination_date = Validate::validate($termination_date, 'termination_date',
|
||||||
|
Validate::REGEX_YYYY_MM_DD, '', [
|
||||||
'0000-00-00',
|
'0000-00-00',
|
||||||
'0',
|
'0',
|
||||||
''
|
''
|
||||||
], true);
|
], true);
|
||||||
|
}
|
||||||
if ($termination_date == '0000-00-00' || empty($termination_date)) {
|
if ($termination_date == '0000-00-00' || empty($termination_date)) {
|
||||||
$termination_date = null;
|
$termination_date = null;
|
||||||
}
|
}
|
||||||
@@ -1478,6 +1501,11 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$mod_fcgid_maxrequests = $result['mod_fcgid_maxrequests'];
|
$mod_fcgid_maxrequests = $result['mod_fcgid_maxrequests'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check changes of openbasedir-path variable
|
||||||
|
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
|
||||||
|
$openbasedir_path = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check non-ssl IP
|
// check non-ssl IP
|
||||||
$ipandports = $this->validateIpAddresses($p_ipandports, false, $result['id']);
|
$ipandports = $this->validateIpAddresses($p_ipandports, false, $result['id']);
|
||||||
// check ssl IP
|
// check ssl IP
|
||||||
@@ -1523,7 +1551,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
||||||
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
||||||
$domain_ips = PhpHelper::gethostbynamel6($result['domain']);
|
$domain_ips = PhpHelper::gethostbynamel6($result['domain'], true, Settings::Get('system.le_domain_dnscheck_resolver'));
|
||||||
$selected_ips = $this->getIpsFromIdArray($ssl_ipandports);
|
$selected_ips = $this->getIpsFromIdArray($ssl_ipandports);
|
||||||
if ($domain_ips == false || count(array_intersect($selected_ips, $domain_ips)) <= 0) {
|
if ($domain_ips == false || count(array_intersect($selected_ips, $domain_ips)) <= 0) {
|
||||||
Response::standardError('invaliddnsforletsencrypt', '', true);
|
Response::standardError('invaliddnsforletsencrypt', '', true);
|
||||||
@@ -1623,7 +1651,31 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
||||||
$iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0';
|
$iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0';
|
||||||
|
|
||||||
if ($documentroot != $result['documentroot'] || $ssl_redirect != $result['ssl_redirect'] || $wwwserveralias != $result['wwwserveralias'] || $iswildcarddomain != $result['iswildcarddomain'] || $phpenabled != $result['phpenabled'] || $openbasedir != $result['openbasedir'] || $phpsettingid != $result['phpsettingid'] || $mod_fcgid_starter != $result['mod_fcgid_starter'] || $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests'] || $specialsettings != $result['specialsettings'] || $ssl_specialsettings != $result['ssl_specialsettings'] || $notryfiles != $result['notryfiles'] || $writeaccesslog != $result['writeaccesslog'] || $writeerrorlog != $result['writeerrorlog'] || $aliasdomain != $result['aliasdomain'] || $issubof != $result['ismainbutsubto'] || $email_only != $result['email_only'] || ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1') || $letsencrypt != $result['letsencrypt'] || $http2 != $result['http2'] || $hsts_maxage != $result['hsts'] || $hsts_sub != $result['hsts_sub'] || $hsts_preload != $result['hsts_preload'] || $ocsp_stapling != $result['ocsp_stapling']) {
|
if ($documentroot != $result['documentroot']
|
||||||
|
|| $ssl_redirect != $result['ssl_redirect']
|
||||||
|
|| $wwwserveralias != $result['wwwserveralias']
|
||||||
|
|| $iswildcarddomain != $result['iswildcarddomain']
|
||||||
|
|| $phpenabled != $result['phpenabled']
|
||||||
|
|| $openbasedir != $result['openbasedir']
|
||||||
|
|| $phpsettingid != $result['phpsettingid']
|
||||||
|
|| $mod_fcgid_starter != $result['mod_fcgid_starter']
|
||||||
|
|| $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests']
|
||||||
|
|| $specialsettings != $result['specialsettings']
|
||||||
|
|| $ssl_specialsettings != $result['ssl_specialsettings']
|
||||||
|
|| $notryfiles != $result['notryfiles']
|
||||||
|
|| $writeaccesslog != $result['writeaccesslog']
|
||||||
|
|| $writeerrorlog != $result['writeerrorlog']
|
||||||
|
|| $aliasdomain != $result['aliasdomain']
|
||||||
|
|| $issubof != $result['ismainbutsubto']
|
||||||
|
|| $email_only != $result['email_only']
|
||||||
|
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|
||||||
|
|| $letsencrypt != $result['letsencrypt']
|
||||||
|
|| $http2 != $result['http2']
|
||||||
|
|| $hsts_maxage != $result['hsts']
|
||||||
|
|| $hsts_sub != $result['hsts_sub']
|
||||||
|
|| $hsts_preload != $result['hsts_preload']
|
||||||
|
|| $ocsp_stapling != $result['ocsp_stapling']
|
||||||
|
) {
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1771,7 +1823,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$update_data['wwwserveralias'] = $wwwserveralias;
|
$update_data['wwwserveralias'] = $wwwserveralias;
|
||||||
$update_data['iswildcarddomain'] = $iswildcarddomain;
|
$update_data['iswildcarddomain'] = $iswildcarddomain;
|
||||||
$update_data['phpenabled'] = $phpenabled;
|
$update_data['phpenabled'] = $phpenabled;
|
||||||
$update_data['openbasedir'] = $openbasedir;
|
$update_data['openbasedir'] = $openbasedir;;
|
||||||
|
$update_data['openbasedir_path'] = $openbasedir_path;
|
||||||
$update_data['speciallogfile'] = $speciallogfile;
|
$update_data['speciallogfile'] = $speciallogfile;
|
||||||
$update_data['phpsettingid'] = $phpsettingid;
|
$update_data['phpsettingid'] = $phpsettingid;
|
||||||
$update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
$update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
||||||
@@ -1819,6 +1872,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`iswildcarddomain` = :iswildcarddomain,
|
`iswildcarddomain` = :iswildcarddomain,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`speciallogfile` = :speciallogfile,
|
`speciallogfile` = :speciallogfile,
|
||||||
`phpsettingid` = :phpsettingid,
|
`phpsettingid` = :phpsettingid,
|
||||||
`mod_fcgid_starter` = :mod_fcgid_starter,
|
`mod_fcgid_starter` = :mod_fcgid_starter,
|
||||||
@@ -1854,6 +1908,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$_update_data['adminid'] = $adminid;
|
$_update_data['adminid'] = $adminid;
|
||||||
$_update_data['phpenabled'] = $phpenabled;
|
$_update_data['phpenabled'] = $phpenabled;
|
||||||
$_update_data['openbasedir'] = $openbasedir;
|
$_update_data['openbasedir'] = $openbasedir;
|
||||||
|
$_update_data['openbasedir_path'] = $openbasedir_path;
|
||||||
$_update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
$_update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
||||||
$_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests;
|
$_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests;
|
||||||
$_update_data['notryfiles'] = $notryfiles;
|
$_update_data['notryfiles'] = $notryfiles;
|
||||||
@@ -1887,6 +1942,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`adminid` = :adminid,
|
`adminid` = :adminid,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`mod_fcgid_starter` = :mod_fcgid_starter,
|
`mod_fcgid_starter` = :mod_fcgid_starter,
|
||||||
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
||||||
`notryfiles` = :notryfiles,
|
`notryfiles` = :notryfiles,
|
||||||
@@ -1903,6 +1959,18 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
");
|
");
|
||||||
Database::pexecute($_update_stmt, $_update_data, true, true);
|
Database::pexecute($_update_stmt, $_update_data, true, true);
|
||||||
|
|
||||||
|
// get current ip<>domain entries
|
||||||
|
$ip_sel_stmt = Database::prepare("
|
||||||
|
SELECT id_ipandports FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
||||||
|
");
|
||||||
|
Database::pexecute($ip_sel_stmt, [
|
||||||
|
'id' => $id
|
||||||
|
], true, true);
|
||||||
|
$current_ips = [];
|
||||||
|
while ($cIP = $ip_sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$current_ips[] = $cIP['id_ipandports'];
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup domain <-> ip mapping
|
// Cleanup domain <-> ip mapping
|
||||||
$del_stmt = Database::prepare("
|
$del_stmt = Database::prepare("
|
||||||
DELETE FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
DELETE FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
||||||
@@ -1930,6 +1998,12 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check ip changes
|
||||||
|
$all_new_ips = array_merge($ipandports, $ssl_ipandports);
|
||||||
|
if (count(array_diff($current_ips, $all_new_ips)) != 0 || count(array_diff($all_new_ips, $current_ips)) != 0) {
|
||||||
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup domain <-> ip mapping for subdomains
|
// Cleanup domain <-> ip mapping for subdomains
|
||||||
$domainidsresult_stmt = Database::prepare("
|
$domainidsresult_stmt = Database::prepare("
|
||||||
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `parentdomainid` = :id
|
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `parentdomainid` = :id
|
||||||
@@ -1974,12 +2048,11 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
if ($result['wwwserveralias'] != $wwwserveralias || $result['letsencrypt'] != $letsencrypt) {
|
if ($result['wwwserveralias'] != $wwwserveralias || $result['letsencrypt'] != $letsencrypt) {
|
||||||
// or when wwwserveralias or letsencrypt was changed
|
// or when wwwserveralias or letsencrypt was changed
|
||||||
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $this->logger());
|
|
||||||
if ((int)$aliasdomain === 0) {
|
if ((int)$aliasdomain === 0) {
|
||||||
// in case the wwwserveralias is set on a main domain, $aliasdomain is 0
|
// in case the wwwserveralias is set on a main domain, $aliasdomain is 0
|
||||||
// --> the call just above to triggerLetsEncryptCSRForAliasDestinationDomain
|
|
||||||
// is a noop...let's repeat it with the domain id of the main domain
|
|
||||||
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($id, $this->logger());
|
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($id, $this->logger());
|
||||||
|
} else {
|
||||||
|
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $this->logger());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2138,7 +2211,9 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
'domainid' => $id
|
'domainid' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
|
if ((int)$result['aliasdomain'] !== 0) {
|
||||||
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger());
|
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger());
|
||||||
|
}
|
||||||
|
|
||||||
// remove domains DNS from powerDNS if used, #581
|
// remove domains DNS from powerDNS if used, #581
|
||||||
Cronjob::inserttask(TaskId::DELETE_DOMAIN_PDNS, $result['domain']);
|
Cronjob::inserttask(TaskId::DELETE_DOMAIN_PDNS, $result['domain']);
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
* @param string $alternative_email
|
* @param string $alternative_email
|
||||||
* optional email address to send account information to, default is the account that is being created
|
* optional email address to send account information to, default is the account that is being created
|
||||||
* @param int $email_quota
|
* @param int $email_quota
|
||||||
* optional quota if enabled in MB, default 0
|
* optional quota if enabled in MB, default setting: system.mail_quota
|
||||||
* @param bool $sendinfomail
|
* @param bool $sendinfomail
|
||||||
* optional, sends the welcome message to the new account (needed for creation, without the user won't
|
* optional, sends the welcome message to the new account (needed for creation, without the user won't
|
||||||
* be able to login before any mail is received), default 1 (true)
|
* be able to login before any mail is received), default 1 (true)
|
||||||
@@ -85,7 +85,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
||||||
$email_password = $this->getParam('email_password');
|
$email_password = $this->getParam('email_password');
|
||||||
$alternative_email = $this->getParam('alternative_email', true, '');
|
$alternative_email = $this->getParam('alternative_email', true, '');
|
||||||
$quota = $this->getParam('email_quota', true, 0);
|
$quota = $this->getParam('email_quota', true, Settings::Get('system.mail_quota') ?? 0);
|
||||||
$sendinfomail = $this->getBoolParam('sendinfomail', true, 1);
|
$sendinfomail = $this->getBoolParam('sendinfomail', true, 1);
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
|
|||||||
188
lib/Froxlor/Api/Commands/EmailDomains.php
Normal file
188
lib/Froxlor/Api/Commands/EmailDomains.php
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Api\Commands;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\Api\ApiCommand;
|
||||||
|
use Froxlor\Api\ResourceEntity;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class EmailDomains extends ApiCommand implements ResourceEntity
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* list all domains with email addresses connected to it.
|
||||||
|
* If called from an admin, list all domains with email addresses
|
||||||
|
* connected to it from all customers you are allowed to view, or
|
||||||
|
* specify id or loginname for one specific customer
|
||||||
|
*
|
||||||
|
* @param int $customerid
|
||||||
|
* optional, admin-only, select email addresses of a specific customer by id
|
||||||
|
* @param string $loginname
|
||||||
|
* optional, admin-only, select email addresses of a specific customer by loginname
|
||||||
|
* @param array $sql_search
|
||||||
|
* optional array with index = fieldname, and value = array with 'op' => operator (one of <, > or =),
|
||||||
|
* LIKE is used if left empty and 'value' => searchvalue
|
||||||
|
* @param int $sql_limit
|
||||||
|
* optional specify number of results to be returned
|
||||||
|
* @param int $sql_offset
|
||||||
|
* optional specify offset for resultset
|
||||||
|
* @param array $sql_orderby
|
||||||
|
* optional array with index = fieldname and value = ASC|DESC to order the resultset by one or more
|
||||||
|
* fields
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array count|list
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function listing()
|
||||||
|
{
|
||||||
|
$customer_ids = $this->getAllowedCustomerIds('email');
|
||||||
|
$result = [];
|
||||||
|
$query_fields = [];
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT DISTINCT d.domain, e.domainid,
|
||||||
|
COUNT(e.email) as addresses,
|
||||||
|
IFNULL(SUM(CASE WHEN e.popaccountid > 0 THEN 1 ELSE 0 END), 0) as accounts,
|
||||||
|
IFNULL(SUM(
|
||||||
|
CASE
|
||||||
|
WHEN LENGTH(REPLACE(e.destination, CONCAT(e.email_full, ' '), '')) - LENGTH(REPLACE(REPLACE(e.destination, CONCAT(e.email_full, ' '), ''), ' ', '')) > 0
|
||||||
|
THEN LENGTH(REPLACE(e.destination, CONCAT(e.email_full, ' '), '')) - LENGTH(REPLACE(REPLACE(e.destination, CONCAT(e.email_full, ' '), ''), ' ', ''))
|
||||||
|
WHEN e.destination <> e.email_full THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END
|
||||||
|
), 0) as forwarder
|
||||||
|
FROM `" . TABLE_MAIL_VIRTUAL . "` e
|
||||||
|
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON d.id = e.domainid
|
||||||
|
WHERE e.customerid IN (" . implode(", ", $customer_ids) . ") AND d.domain IS NOT NULL " .
|
||||||
|
$this->getSearchWhere($query_fields,
|
||||||
|
true) . " GROUP BY e.domainid " . $this->getOrderBy() . $this->getLimit());
|
||||||
|
Database::pexecute($result_stmt, $query_fields, true, true);
|
||||||
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$result[] = $row;
|
||||||
|
}
|
||||||
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE,
|
||||||
|
"[API] list email-domains");
|
||||||
|
return $this->response([
|
||||||
|
'count' => count($result),
|
||||||
|
'list' => $result
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the total number of accessible domains with email addresses connected to
|
||||||
|
*
|
||||||
|
* @param int $customerid
|
||||||
|
* optional, admin-only, select email addresses of a specific customer by id
|
||||||
|
* @param string $loginname
|
||||||
|
* optional, admin-only, select email addresses of a specific customer by loginname
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded response message
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function listingCount()
|
||||||
|
{
|
||||||
|
$customer_ids = $this->getAllowedCustomerIds('email');
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT COUNT(DISTINCT d.domain) as num_emaildomains
|
||||||
|
FROM `" . TABLE_MAIL_VIRTUAL . "` e
|
||||||
|
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON d.id = e.domainid
|
||||||
|
WHERE e.customerid IN (" . implode(", ", $customer_ids) . ") AND d.domain IS NOT NULL
|
||||||
|
");
|
||||||
|
$result = Database::pexecute_first($result_stmt, null, true, true);
|
||||||
|
if ($result) {
|
||||||
|
return $this->response($result['num_emaildomains']);
|
||||||
|
}
|
||||||
|
return $this->response(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You cannot directly access email-domains
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function get()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
|
||||||
|
throw new Exception("You cannot access this resource", 405);
|
||||||
|
}
|
||||||
|
throw new Exception('You cannot directly access this resource.', 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You cannot directly add email-domains
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
|
||||||
|
throw new Exception("You cannot access this resource", 405);
|
||||||
|
}
|
||||||
|
throw new Exception('You cannot directly add this resource.', 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toggle catchall flag of given email address either by id or email-address
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
|
||||||
|
throw new Exception("You cannot access this resource", 405);
|
||||||
|
}
|
||||||
|
throw new Exception('You cannot directly update this resource.', 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You cannot directly delete email-domains
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
|
||||||
|
throw new Exception("You cannot access this resource", 405);
|
||||||
|
}
|
||||||
|
throw new Exception('You cannot directly delete this resource.', 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -195,8 +195,8 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
FROM `" . TABLE_MAIL_VIRTUAL . "` v
|
FROM `" . TABLE_MAIL_VIRTUAL . "` v
|
||||||
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
|
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
|
||||||
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
|
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
|
||||||
AND (v.`id`= :idea OR (v.`email` = :idea OR v.`email_full` = :idea))
|
AND " . (is_numeric($params['idea']) ? "v.`id`= :idea" : "(v.`email` = :idea OR v.`email_full` = :idea)")
|
||||||
");
|
);
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get email address '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get email address '" . $result['email_full'] . "'");
|
||||||
|
|||||||
@@ -516,7 +516,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
`allowed_mysqlserver` = :am WHERE `customerid` = :cid
|
`allowed_mysqlserver` = :am WHERE `customerid` = :cid
|
||||||
");
|
");
|
||||||
while ($customer = $sel_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($customer = $sel_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$allowed_mysqls = json_decode(($customer['allowed_mysqlserver'] ?? '[]'), true);
|
$allowed_mysqls = json_decode(($customer['allowed_mysqlserver'] ?: '[]'), true);
|
||||||
if (!in_array($dbserver, $allowed_mysqls)) {
|
if (!in_array($dbserver, $allowed_mysqls)) {
|
||||||
$allowed_mysqls[] = $dbserver;
|
$allowed_mysqls[] = $dbserver;
|
||||||
$allowed_mysqls = json_encode($allowed_mysqls);
|
$allowed_mysqls = json_encode($allowed_mysqls);
|
||||||
|
|||||||
@@ -73,12 +73,12 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
$password = $this->getParam('mysql_password');
|
$password = $this->getParam('mysql_password');
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
$dbserver = $this->getParam('mysql_server', true, 0);
|
|
||||||
$databasedescription = $this->getParam('description', true, '');
|
$databasedescription = $this->getParam('description', true, '');
|
||||||
$databasename = $this->getParam('custom_suffix', true, '');
|
$databasename = $this->getParam('custom_suffix', true, '');
|
||||||
$sendinfomail = $this->getBoolParam('sendinfomail', true, 0);
|
$sendinfomail = $this->getBoolParam('sendinfomail', true, 0);
|
||||||
// get needed customer info to reduce the mysql-usage-counter by one
|
// get needed customer info to reduce the mysql-usage-counter by one
|
||||||
$customer = $this->getCustomerData('mysqls');
|
$customer = $this->getCustomerData('mysqls');
|
||||||
|
$dbserver = $this->getParam('mysql_server', true, $this->getDefaultMySqlServer($customer));
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$password = Validate::validate($password, 'password', '', '', [], true);
|
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||||
@@ -90,7 +90,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validate whether the dbserver exists
|
// validate whether the dbserver exists
|
||||||
$dbserver = Validate::validate($dbserver, html_entity_decode(lng('mysql.mysql_server')), '/^[0-9]+$/', '', 0, true);
|
$dbserver = Validate::validate($dbserver, html_entity_decode(lng('mysql.mysql_server')), '/^[0-9]+$/', '', 0, true);
|
||||||
Database::needRoot(true, $dbserver);
|
Database::needRoot(true, $dbserver, false);
|
||||||
Database::needSqlData();
|
Database::needSqlData();
|
||||||
$sql_root = Database::getSqlData();
|
$sql_root = Database::getSqlData();
|
||||||
Database::needRoot(false);
|
Database::needRoot(false);
|
||||||
@@ -150,7 +150,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
$pma = Settings::Get('panel.phpmyadmin_url');
|
$pma = Settings::Get('panel.phpmyadmin_url');
|
||||||
}
|
}
|
||||||
|
|
||||||
Database::needRoot(true, $dbserver);
|
Database::needRoot(true, $dbserver, false);
|
||||||
Database::needSqlData();
|
Database::needSqlData();
|
||||||
$sql_root = Database::getSqlData();
|
$sql_root = Database::getSqlData();
|
||||||
Database::needRoot(false);
|
Database::needRoot(false);
|
||||||
@@ -287,7 +287,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
Database::needRoot(true, $result['dbserver']);
|
Database::needRoot(true, $result['dbserver'], false);
|
||||||
$mbdata_stmt = Database::prepare("
|
$mbdata_stmt = Database::prepare("
|
||||||
SELECT SUM(data_length + index_length) as MB FROM information_schema.TABLES
|
SELECT SUM(data_length + index_length) as MB FROM information_schema.TABLES
|
||||||
WHERE table_schema = :table_schema
|
WHERE table_schema = :table_schema
|
||||||
@@ -364,7 +364,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Begin root-session
|
// Begin root-session
|
||||||
Database::needRoot(true, $result['dbserver']);
|
Database::needRoot(true, $result['dbserver'], false);
|
||||||
$dbmgr = new DbManager($this->logger());
|
$dbmgr = new DbManager($this->logger());
|
||||||
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
|
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
|
||||||
$dbmgr->getManager()->grantPrivilegesTo($result['databasename'], $password, $mysql_access_host, false, true);
|
$dbmgr->getManager()->grantPrivilegesTo($result['databasename'], $password, $mysql_access_host, false, true);
|
||||||
@@ -449,7 +449,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
'dbserver' => $_dbserver['dbserver']
|
'dbserver' => $_dbserver['dbserver']
|
||||||
], $query_fields), true, true);
|
], $query_fields), true, true);
|
||||||
// Begin root-session
|
// Begin root-session
|
||||||
Database::needRoot(true, $_dbserver['dbserver']);
|
Database::needRoot(true, $_dbserver['dbserver'], false);
|
||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$mbdata_stmt = Database::prepare("
|
$mbdata_stmt = Database::prepare("
|
||||||
SELECT SUM(data_length + index_length) as MB FROM information_schema.TABLES
|
SELECT SUM(data_length + index_length) as MB FROM information_schema.TABLES
|
||||||
@@ -536,7 +536,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
$id = $result['id'];
|
$id = $result['id'];
|
||||||
|
|
||||||
// Begin root-session
|
// Begin root-session
|
||||||
Database::needRoot(true, $result['dbserver']);
|
Database::needRoot(true, $result['dbserver'], false);
|
||||||
$dbm = new DbManager($this->logger());
|
$dbm = new DbManager($this->logger());
|
||||||
$dbm->getManager()->deleteDatabase($result['databasename']);
|
$dbm->getManager()->deleteDatabase($result['databasename']);
|
||||||
Database::needRoot(false);
|
Database::needRoot(false);
|
||||||
@@ -558,4 +558,13 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted database '" . $result['databasename'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted database '" . $result['databasename'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getDefaultMySqlServer(array $customer) {
|
||||||
|
$allowed_mysqlservers = json_decode($customer['allowed_mysqlserver'] ?? '[]', true);
|
||||||
|
asort($allowed_mysqlservers, SORT_NUMERIC);
|
||||||
|
if (count($allowed_mysqlservers) == 1 && $allowed_mysqlservers[0] != 0) {
|
||||||
|
return (int) $allowed_mysqlservers[0];
|
||||||
|
}
|
||||||
|
return (int) array_shift($allowed_mysqlservers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, overwrites path value with an URL to generate a redirect, alternatively use the path
|
* optional, overwrites path value with an URL to generate a redirect, alternatively use the path
|
||||||
* parameter also for URLs
|
* parameter also for URLs
|
||||||
* @param int $openbasedir_path
|
* @param int $openbasedir_path
|
||||||
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
* optional, either 0 for domains-docroot [default], 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, php-settings-id, if empty the $domain value is used
|
* optional, php-settings-id, if empty the $domain value is used
|
||||||
* @param int $redirectcode
|
* @param int $redirectcode
|
||||||
@@ -104,7 +104,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$aliasdomain = $this->getParam('alias', true, 0);
|
$aliasdomain = $this->getParam('alias', true, 0);
|
||||||
$path = $this->getParam('path', true, '');
|
$path = $this->getParam('path', true, '');
|
||||||
$url = $this->getParam('url', true, '');
|
$url = $this->getParam('url', true, '');
|
||||||
$openbasedir_path = $this->getParam('openbasedir_path', true, 1);
|
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, 0);
|
$phpsettingid = $this->getParam('phpsettingid', true, 0);
|
||||||
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
|
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
|
||||||
$isemaildomain = $this->getParam('isemaildomain', true, 0);
|
$isemaildomain = $this->getParam('isemaildomain', true, 0);
|
||||||
@@ -262,7 +262,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
||||||
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
||||||
$our_ips = Domain::getIpsOfDomain($domain_check['id']);
|
$our_ips = Domain::getIpsOfDomain($domain_check['id']);
|
||||||
$domain_ips = PhpHelper::gethostbynamel6($completedomain);
|
$domain_ips = PhpHelper::gethostbynamel6($completedomain, true, Settings::Get('system.le_domain_dnscheck_resolver'));
|
||||||
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
||||||
Response::standardError('invaliddnsforletsencrypt', '', true);
|
Response::standardError('invaliddnsforletsencrypt', '', true);
|
||||||
}
|
}
|
||||||
@@ -701,11 +701,13 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$wwwserveralias = ($selectserveralias == '1') ? '1' : '0';
|
$wwwserveralias = ($selectserveralias == '1') ? '1' : '0';
|
||||||
|
|
||||||
// if allowed, check for 'is email domain'-flag
|
// if allowed, check for 'is email domain'-flag
|
||||||
if ($result['parentdomainid'] != '0' && ($result['subcanemaildomain'] == '1' || $result['subcanemaildomain'] == '2') && $isemaildomain != $result['isemaildomain']) {
|
if ($isemaildomain != $result['isemaildomain']) {
|
||||||
|
if ($result['parentdomainid'] != '0' && ($result['subcanemaildomain'] == '1' || $result['subcanemaildomain'] == '2')) {
|
||||||
$isemaildomain = intval($isemaildomain);
|
$isemaildomain = intval($isemaildomain);
|
||||||
} elseif ($result['parentdomainid'] != '0') {
|
} elseif ($result['parentdomainid'] != '0') {
|
||||||
$isemaildomain = $result['subcanemaildomain'] == '3' ? 1 : 0;
|
$isemaildomain = $result['subcanemaildomain'] == '3' ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check changes of openbasedir-path variable
|
// check changes of openbasedir-path variable
|
||||||
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
|
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
|
||||||
@@ -736,7 +738,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
||||||
if ($result['letsencrypt'] != $letsencrypt && $letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
if ($result['letsencrypt'] != $letsencrypt && $letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
||||||
$our_ips = Domain::getIpsOfDomain($result['parentdomainid']);
|
$our_ips = Domain::getIpsOfDomain($result['parentdomainid']);
|
||||||
$domain_ips = PhpHelper::gethostbynamel6($result['domain']);
|
$domain_ips = PhpHelper::gethostbynamel6($result['domain'], true, Settings::Get('system.le_domain_dnscheck_resolver'));
|
||||||
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
||||||
Response::standardError('invaliddnsforletsencrypt', '', true);
|
Response::standardError('invaliddnsforletsencrypt', '', true);
|
||||||
}
|
}
|
||||||
@@ -1131,7 +1133,9 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((int)$result['aliasdomain'] !== 0) {
|
||||||
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger());
|
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger());
|
||||||
|
}
|
||||||
|
|
||||||
// delete domain from table
|
// delete domain from table
|
||||||
$stmt = Database::prepare("
|
$stmt = Database::prepare("
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||||||
class CliCommand extends Command
|
class CliCommand extends Command
|
||||||
{
|
{
|
||||||
|
|
||||||
protected function validateRequirements(InputInterface $input, OutputInterface $output): int
|
protected function validateRequirements(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.</>");
|
||||||
@@ -51,7 +51,7 @@ class CliCommand extends Command
|
|||||||
$output->writeln("<error>" . $e->getMessage() . "</>");
|
$output->writeln("<error>" . $e->getMessage() . "</>");
|
||||||
return self::INVALID;
|
return self::INVALID;
|
||||||
}
|
}
|
||||||
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
if (!$ignore_has_updates && (Froxlor::hasUpdates() || Froxlor::hasDbUpdates())) {
|
||||||
if ((int)Settings::Get('system.cron_allowautoupdate') == 1) {
|
if ((int)Settings::Get('system.cron_allowautoupdate') == 1) {
|
||||||
return $this->runUpdate($output);
|
return $this->runUpdate($output);
|
||||||
} else {
|
} else {
|
||||||
@@ -122,7 +122,7 @@ class CliCommand extends Command
|
|||||||
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
|
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
|
||||||
define('_CRON_UPDATE', 1);
|
define('_CRON_UPDATE', 1);
|
||||||
ob_start([
|
ob_start([
|
||||||
'this',
|
$this,
|
||||||
'cleanUpdateOutput'
|
'cleanUpdateOutput'
|
||||||
]);
|
]);
|
||||||
include_once Froxlor::getInstallDir() . '/install/updatesql.php';
|
include_once Froxlor::getInstallDir() . '/install/updatesql.php';
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ final class InstallCommand extends Command
|
|||||||
$_SERVER['SERVER_NAME'] = $host[0] ?? '';
|
$_SERVER['SERVER_NAME'] = $host[0] ?? '';
|
||||||
$ips = [];
|
$ips = [];
|
||||||
exec('hostname -I', $ips);
|
exec('hostname -I', $ips);
|
||||||
$ips = explode(" ", $ips[0]);
|
$ips = explode(" ", $ips[0] ?? "");
|
||||||
// ipv4 address?
|
// ipv4 address?
|
||||||
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ($ips[0] ?? '') : '';
|
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ($ips[0] ?? '') : '';
|
||||||
if (empty($_SERVER['SERVER_ADDR'])) {
|
if (empty($_SERVER['SERVER_ADDR'])) {
|
||||||
@@ -246,8 +246,11 @@ final class InstallCommand extends Command
|
|||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->io->error($e->getMessage());
|
$this->io->error($e->getMessage());
|
||||||
|
if ($this->io->confirm('Retry?', empty($decoded_input))) {
|
||||||
return $this->showStep($step, $extended, $decoded_input);
|
return $this->showStep($step, $extended, $decoded_input);
|
||||||
}
|
}
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
if ($step == 3) {
|
if ($step == 3) {
|
||||||
// do actual install with data from $this->formfielddata
|
// do actual install with data from $this->formfielddata
|
||||||
$core = new Core($this->formfielddata);
|
$core = new Core($this->formfielddata);
|
||||||
@@ -297,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 == 'manual_config') {
|
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') {
|
||||||
|
|||||||
@@ -62,6 +62,11 @@ final class MasterCron extends CliCommand
|
|||||||
$result = self::SUCCESS;
|
$result = self::SUCCESS;
|
||||||
$result = $this->validateRequirements($input, $output);
|
$result = $this->validateRequirements($input, $output);
|
||||||
|
|
||||||
|
if ($result != self::SUCCESS) {
|
||||||
|
// requirements failed, exit
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
$jobs = $input->getArgument('job');
|
$jobs = $input->getArgument('job');
|
||||||
|
|
||||||
// handle force option
|
// handle force option
|
||||||
@@ -111,8 +116,8 @@ final class MasterCron extends CliCommand
|
|||||||
]);
|
]);
|
||||||
$this->cronLog->setCronDebugFlag(defined('CRON_DEBUG_FLAG'));
|
$this->cronLog->setCronDebugFlag(defined('CRON_DEBUG_FLAG'));
|
||||||
|
|
||||||
// check whether there are actual tasks to perform by 'tasks'-cron so
|
// check whether there are actual tasks to perform by 'tasks'-cron, so
|
||||||
// we dont regenerate files unnecessarily
|
// we don't regenerate files unnecessarily
|
||||||
$tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`");
|
$tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`");
|
||||||
$tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC);
|
$tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
|||||||
165
lib/Froxlor/Cli/ValidateAcmeWebroot.php
Normal file
165
lib/Froxlor/Cli/ValidateAcmeWebroot.php
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
|
use Froxlor\Cron\TaskId;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
use Froxlor\System\Cronjob;
|
||||||
|
use PDO;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
final class ValidateAcmeWebroot extends CliCommand
|
||||||
|
{
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('froxlor:validate-acme-webroot');
|
||||||
|
$this->setDescription('Validates the Le_Webroot value is correct for froxlor managed domains with Let\'s Encrypt certificate.');
|
||||||
|
$this->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for confirmation, update files if necessary');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$result = self::SUCCESS;
|
||||||
|
|
||||||
|
$result = $this->validateRequirements($input, $output, true);
|
||||||
|
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
|
||||||
|
if ((int) Settings::Get('system.leenabled') == 0) {
|
||||||
|
$io->info("Let's Encrypt not activated in froxlor settings.");
|
||||||
|
$result = self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result == self::SUCCESS) {
|
||||||
|
$yestoall = $input->getOption('yes-to-all') !== false;
|
||||||
|
$helper = $this->getHelper('question');
|
||||||
|
$count_changes = 0;
|
||||||
|
// get all Let's Encrypt enabled domains
|
||||||
|
$sel_stmt = Database::prepare("SELECT id, domain FROM panel_domains WHERE `letsencrypt` = '1' AND aliasdomain IS NULL ORDER BY id ASC");
|
||||||
|
Database::pexecute($sel_stmt);
|
||||||
|
$domains = $sel_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
// check for froxlor-vhost
|
||||||
|
if (Settings::Get('system.le_froxlor_enabled') == '1') {
|
||||||
|
$domains[] = [
|
||||||
|
'id' => 0,
|
||||||
|
'domain' => Settings::Get('system.hostname')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$upd_stmt = Database::prepare("UPDATE domain_ssl_settings SET `validtodate`=NULL WHERE `domainid` = :did");
|
||||||
|
$acmesh_dir = dirname(Settings::Get('system.acmeshpath'));
|
||||||
|
$acmesh_challenge_dir = rtrim(FileDir::makeCorrectDir(Settings::Get('system.letsencryptchallengepath')), "/");
|
||||||
|
$recommended = rtrim(FileDir::makeCorrectDir(Froxlor::getInstallDir()), "/");
|
||||||
|
|
||||||
|
if ($acmesh_challenge_dir != $recommended) {
|
||||||
|
$io->warning([
|
||||||
|
"ACME challenge docroot from settings differs from the current installation directory.",
|
||||||
|
"Settings: '" . $acmesh_challenge_dir . "'",
|
||||||
|
"Default/recommended value: '" . $recommended . "'",
|
||||||
|
]);
|
||||||
|
$question = new ConfirmationQuestion('Fix ACME challenge docroot setting? [yes] ', true, '/^(y|j)/i');
|
||||||
|
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||||
|
Settings::Set('system.letsencryptchallengepath', $recommended);
|
||||||
|
$former_value = $acmesh_challenge_dir;
|
||||||
|
$acmesh_challenge_dir = $recommended;
|
||||||
|
// need to update the corresponding acme-alias config-file
|
||||||
|
$acme_alias_file = Settings::Get('system.letsencryptacmeconf');
|
||||||
|
$sed_params = "s@".$former_value."@" . $acmesh_challenge_dir . "@";
|
||||||
|
FileDir::safe_exec('sed -i -e "' . $sed_params . '" ' . escapeshellarg($acme_alias_file));
|
||||||
|
$count_changes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($domains as $domain_arr) {
|
||||||
|
$domain = $domain_arr['domain'];
|
||||||
|
$acme_domain_conf = FileDir::makeCorrectFile($acmesh_dir . '/' . $domain . '/' . $domain . '.conf');
|
||||||
|
if (file_exists($acme_domain_conf)) {
|
||||||
|
$io->text("Getting info from " . $acme_domain_conf);
|
||||||
|
$conf_content = file_get_contents($acme_domain_conf);
|
||||||
|
} else {
|
||||||
|
$acme_domain_conf = FileDir::makeCorrectFile($acmesh_dir . '/' . $domain . '_ecc/' . $domain . '.conf');
|
||||||
|
if (file_exists($acme_domain_conf)) {
|
||||||
|
$io->text("Getting info from " . $acme_domain_conf);
|
||||||
|
$conf_content = file_get_contents($acme_domain_conf);
|
||||||
|
} else {
|
||||||
|
$io->info("No domain configuration file found in '" . $acmesh_dir . "'");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($conf_content)) {
|
||||||
|
$lines = explode("\n", $conf_content);
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
$val_key = explode("=", $line);
|
||||||
|
if ($val_key[0] == 'Le_Webroot') {
|
||||||
|
$domain_webroot = trim(trim($val_key[1], "'"), '"');
|
||||||
|
if ($domain_webroot != $acmesh_challenge_dir) {
|
||||||
|
$io->warning("Domain '" . $domain . "' has old/wrong Le_Webroot setting: '" . $domain_webroot . ' <> ' . $acmesh_challenge_dir . "'");
|
||||||
|
$question = new ConfirmationQuestion('Fix Le_Webroot? [yes] ', true, '/^(y|j)/i');
|
||||||
|
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||||
|
$sed_params = "s@Le_Webroot=.*@Le_Webroot='" . $acmesh_challenge_dir . "'@";
|
||||||
|
FileDir::safe_exec('sed -i -e "' . $sed_params . '" ' . escapeshellarg($acme_domain_conf));
|
||||||
|
Database::pexecute($upd_stmt, ['did' => $domain_arr['id']]);
|
||||||
|
$io->success("Correction of Le_Webroot successful");
|
||||||
|
$count_changes++;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$io->info("Domain '" . $domain . "' Le_Webroot value is correct");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($count_changes > 0) {
|
||||||
|
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
||||||
|
$io->info("Changes detected but froxlor has been updated. Inserting task to rebuild vhosts after update.");
|
||||||
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
} else {
|
||||||
|
$question = new ConfirmationQuestion('Changes detected. Force cronjob to refresh certificates? [yes] ', true, '/^(y|j)/i');
|
||||||
|
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||||
|
passthru(FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -f -d');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$io->success("No changes necessary.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -148,7 +148,7 @@ class ConfigDisplay
|
|||||||
if ($lasttype != '' && $lasttype != $_action['type']) {
|
if ($lasttype != '' && $lasttype != $_action['type']) {
|
||||||
$commands = trim($commands);
|
$commands = trim($commands);
|
||||||
$numbrows = count(explode("\n", $commands));
|
$numbrows = count(explode("\n", $commands));
|
||||||
$configpage .= UI::twig()->render(self::$theme . '/settings/conf/command.html.twig', [
|
$configpage .= UI::twig()->render(UI::validateThemeTemplate('/settings/conf/command.html.twig', self::$theme), [
|
||||||
'commands' => $commands,
|
'commands' => $commands,
|
||||||
'numbrows' => $numbrows
|
'numbrows' => $numbrows
|
||||||
]);
|
]);
|
||||||
@@ -182,7 +182,7 @@ class ConfigDisplay
|
|||||||
$commands = trim($commands_pre);
|
$commands = trim($commands_pre);
|
||||||
if ($commands != "") {
|
if ($commands != "") {
|
||||||
$numbrows = count(explode("\n", $commands));
|
$numbrows = count(explode("\n", $commands));
|
||||||
$commands_pre = UI::twig()->render(self::$theme . '/settings/conf/command.html.twig', [
|
$commands_pre = UI::twig()->render(UI::validateThemeTemplate('/settings/conf/command.html.twig', self::$theme), [
|
||||||
'commands' => $commands,
|
'commands' => $commands,
|
||||||
'numbrows' => $numbrows
|
'numbrows' => $numbrows
|
||||||
]);
|
]);
|
||||||
@@ -190,12 +190,12 @@ class ConfigDisplay
|
|||||||
$commands = trim($commands_post);
|
$commands = trim($commands_post);
|
||||||
if ($commands != "") {
|
if ($commands != "") {
|
||||||
$numbrows = count(explode("\n", $commands));
|
$numbrows = count(explode("\n", $commands));
|
||||||
$commands_post = UI::twig()->render(self::$theme . '/settings/conf/command.html.twig', [
|
$commands_post = UI::twig()->render(UI::validateThemeTemplate('/settings/conf/command.html.twig', self::$theme), [
|
||||||
'commands' => $commands,
|
'commands' => $commands,
|
||||||
'numbrows' => $numbrows
|
'numbrows' => $numbrows
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$configpage .= UI::twig()->render(self::$theme . '/settings/conf/fileblock.html.twig', [
|
$configpage .= UI::twig()->render(UI::validateThemeTemplate('/settings/conf/fileblock.html.twig', self::$theme), [
|
||||||
'realname' => $realname,
|
'realname' => $realname,
|
||||||
'commands_pre' => $commands_pre,
|
'commands_pre' => $commands_pre,
|
||||||
'commands_file' => $commands_file,
|
'commands_file' => $commands_file,
|
||||||
@@ -210,7 +210,7 @@ class ConfigDisplay
|
|||||||
$commands = trim($commands);
|
$commands = trim($commands);
|
||||||
if ($commands != '') {
|
if ($commands != '') {
|
||||||
$numbrows = count(explode("\n", $commands));
|
$numbrows = count(explode("\n", $commands));
|
||||||
$configpage .= UI::twig()->render(self::$theme . '/settings/conf/command.html.twig', [
|
$configpage .= UI::twig()->render(UI::validateThemeTemplate('/settings/conf/command.html.twig', self::$theme), [
|
||||||
'commands' => $commands,
|
'commands' => $commands,
|
||||||
'numbrows' => $numbrows
|
'numbrows' => $numbrows
|
||||||
]);
|
]);
|
||||||
@@ -233,7 +233,7 @@ class ConfigDisplay
|
|||||||
$file_content = htmlspecialchars($file_content);
|
$file_content = htmlspecialchars($file_content);
|
||||||
$numbrows = count(explode("\n", $file_content));
|
$numbrows = count(explode("\n", $file_content));
|
||||||
//eval("\$files=\"" . \Froxlor\UI\Template::getTemplate("configfiles/configfiles_file") . "\";");
|
//eval("\$files=\"" . \Froxlor\UI\Template::getTemplate("configfiles/configfiles_file") . "\";");
|
||||||
$files = UI::twig()->render(self::$theme . '/settings/conf/file.html.twig', [
|
$files = UI::twig()->render(UI::validateThemeTemplate('/settings/conf/file.html.twig', self::$theme), [
|
||||||
'distro_editor' => self::$editor,
|
'distro_editor' => self::$editor,
|
||||||
'realname' => $realname,
|
'realname' => $realname,
|
||||||
'numbrows' => $numbrows,
|
'numbrows' => $numbrows,
|
||||||
|
|||||||
@@ -613,7 +613,10 @@ class Apache extends HttpConfigBase
|
|||||||
// Apply header
|
// Apply header
|
||||||
$this->virtualhosts_data[$vhosts_filename] = '# Domain ID: ' . $domain['id'] . ' - CustomerID: ' . $domain['customerid'] . ' - CustomerLogin: ' . $domain['loginname'] . "\n";
|
$this->virtualhosts_data[$vhosts_filename] = '# Domain ID: ' . $domain['id'] . ' - CustomerID: ' . $domain['customerid'] . ' - CustomerLogin: ' . $domain['loginname'] . "\n";
|
||||||
|
|
||||||
if ($domain['deactivated'] != '1' || Settings::Get('system.deactivateddocroot') != '') {
|
$ddr = Settings::Get('system.deactivateddocroot');
|
||||||
|
if (($domain['deactivated'] == '1' || $domain['customer_deactivated'] == '1') && empty($ddr)) {
|
||||||
|
$this->virtualhosts_data[$vhosts_filename] .= '# Customer/domain deactivated and a docroot for deactivated users hasn\'t been set.' . "\n";
|
||||||
|
} else {
|
||||||
// Create vhost without ssl
|
// Create vhost without ssl
|
||||||
$this->virtualhosts_data[$vhosts_filename] .= $this->getVhostContent($domain, false);
|
$this->virtualhosts_data[$vhosts_filename] .= $this->getVhostContent($domain, false);
|
||||||
|
|
||||||
@@ -623,8 +626,6 @@ class Apache extends HttpConfigBase
|
|||||||
$this->virtualhosts_data[$vhosts_filename_ssl] = '# Domain ID: ' . $domain['id'] . ' (SSL) - CustomerID: ' . $domain['customerid'] . ' - CustomerLogin: ' . $domain['loginname'] . "\n";
|
$this->virtualhosts_data[$vhosts_filename_ssl] = '# Domain ID: ' . $domain['id'] . ' (SSL) - CustomerID: ' . $domain['customerid'] . ' - CustomerLogin: ' . $domain['loginname'] . "\n";
|
||||||
$this->virtualhosts_data[$vhosts_filename_ssl] .= $this->getVhostContent($domain, true);
|
$this->virtualhosts_data[$vhosts_filename_ssl] .= $this->getVhostContent($domain, true);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$this->virtualhosts_data[$vhosts_filename] .= '# Customer deactivated and a docroot for deactivated users hasn\'t been set.' . "\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -840,6 +841,8 @@ class Apache extends HttpConfigBase
|
|||||||
$domain['documentroot'] = trim($domain['documentroot']);
|
$domain['documentroot'] = trim($domain['documentroot']);
|
||||||
|
|
||||||
if (preg_match('/^https?\:\/\//', $domain['documentroot'])) {
|
if (preg_match('/^https?\:\/\//', $domain['documentroot'])) {
|
||||||
|
$possible_deactivated_webroot = $this->getWebroot($domain);
|
||||||
|
if ($this->deactivated == false) {
|
||||||
$corrected_docroot = $domain['documentroot'];
|
$corrected_docroot = $domain['documentroot'];
|
||||||
|
|
||||||
// Get domain's redirect code
|
// Get domain's redirect code
|
||||||
@@ -863,6 +866,9 @@ class Apache extends HttpConfigBase
|
|||||||
$vhost_content .= ' <IfModule !mod_rewrite.c>' . "\n";
|
$vhost_content .= ' <IfModule !mod_rewrite.c>' . "\n";
|
||||||
$vhost_content .= ' Redirect ' . $code . ' / ' . $domain['documentroot_norewrite'] . "\n";
|
$vhost_content .= ' Redirect ' . $code . ' / ' . $domain['documentroot_norewrite'] . "\n";
|
||||||
$vhost_content .= ' </IfModule>' . "\n";
|
$vhost_content .= ' </IfModule>' . "\n";
|
||||||
|
} elseif (Settings::Get('system.deactivateddocroot') != '') {
|
||||||
|
$vhost_content .= $possible_deactivated_webroot;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
FileDir::mkDirWithCorrectOwnership($domain['customerroot'], $domain['documentroot'], $domain['guid'], $domain['guid'], true, true);
|
FileDir::mkDirWithCorrectOwnership($domain['customerroot'], $domain['documentroot'], $domain['guid'], $domain['guid'], true, true);
|
||||||
$vhost_content .= $this->getWebroot($domain);
|
$vhost_content .= $this->getWebroot($domain);
|
||||||
@@ -952,8 +958,8 @@ class Apache extends HttpConfigBase
|
|||||||
$domain['customerroot'] = FileDir::makeCorrectDir($domain['customerroot']);
|
$domain['customerroot'] = FileDir::makeCorrectDir($domain['customerroot']);
|
||||||
$domain['documentroot'] = FileDir::makeCorrectDir($domain['documentroot']);
|
$domain['documentroot'] = FileDir::makeCorrectDir($domain['documentroot']);
|
||||||
|
|
||||||
if ($domain['deactivated'] == '1' && Settings::Get('system.deactivateddocroot') != '') {
|
if (($domain['deactivated'] == '1' || $domain['customer_deactivated'] == '1') && Settings::Get('system.deactivateddocroot') != '') {
|
||||||
$webroot_text .= ' # Using docroot for deactivated users...' . "\n";
|
$webroot_text .= ' # Using docroot for deactivated users/domains...' . "\n";
|
||||||
$webroot_text .= ' DocumentRoot "' . rtrim(FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')), "/") . "\"\n";
|
$webroot_text .= ' DocumentRoot "' . rtrim(FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')), "/") . "\"\n";
|
||||||
$webroot_text .= ' <Directory "' . FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')) . '">' . "\n";
|
$webroot_text .= ' <Directory "' . FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')) . '">' . "\n";
|
||||||
// >=apache-2.4 enabled?
|
// >=apache-2.4 enabled?
|
||||||
@@ -1034,6 +1040,10 @@ class Apache extends HttpConfigBase
|
|||||||
|
|
||||||
$statTool = Settings::Get('system.traffictool');
|
$statTool = Settings::Get('system.traffictool');
|
||||||
$statDomain = "";
|
$statDomain = "";
|
||||||
|
if ($statTool == 'awstats') {
|
||||||
|
// awstats generates for each domain regardless of speciallogfile
|
||||||
|
$statDomain = "/" . $domain['domain'];
|
||||||
|
}
|
||||||
if ($domain['speciallogfile'] == '1') {
|
if ($domain['speciallogfile'] == '1') {
|
||||||
$statDomain = "/" . (($domain['parentdomainid'] == '0') ? $domain['domain'] : $domain['parentdomain']);
|
$statDomain = "/" . (($domain['parentdomainid'] == '0') ? $domain['domain'] : $domain['parentdomain']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,6 +126,9 @@ class ApacheFcgi extends Apache
|
|||||||
|
|
||||||
// mod_proxy stuff for apache-2.4
|
// mod_proxy stuff for apache-2.4
|
||||||
if (Settings::Get('system.apache24') == '1' && Settings::Get('phpfpm.use_mod_proxy') == '1') {
|
if (Settings::Get('system.apache24') == '1' && Settings::Get('phpfpm.use_mod_proxy') == '1') {
|
||||||
|
|
||||||
|
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||||
|
|
||||||
$filesmatch = $phpconfig['fpm_settings']['limit_extensions'];
|
$filesmatch = $phpconfig['fpm_settings']['limit_extensions'];
|
||||||
$extensions = explode(" ", $filesmatch);
|
$extensions = explode(" ", $filesmatch);
|
||||||
$filesmatch = "";
|
$filesmatch = "";
|
||||||
@@ -141,23 +144,19 @@ class ApacheFcgi extends Apache
|
|||||||
$php_options_text .= ' </FilesMatch>' . "\n";
|
$php_options_text .= ' </FilesMatch>' . "\n";
|
||||||
|
|
||||||
$mypath_dir = new Directory($domain['documentroot']);
|
$mypath_dir = new Directory($domain['documentroot']);
|
||||||
|
// only create the "require all granted" directive if there is no active directory-protection
|
||||||
// only create the require all granted if there is not active directory-protection
|
|
||||||
// for this path, as this would be the first require and therefore grant all access
|
// for this path, as this would be the first require and therefore grant all access
|
||||||
if ($mypath_dir->isUserProtected() == false) {
|
if ($mypath_dir->isUserProtected() == false) {
|
||||||
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
|
||||||
if ($phpconfig['pass_authorizationheader'] == '1') {
|
if ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
$php_options_text .= ' CGIPassAuth On' . "\n";
|
$php_options_text .= ' CGIPassAuth On' . "\n";
|
||||||
}
|
}
|
||||||
$php_options_text .= ' Require all granted' . "\n";
|
$php_options_text .= ' Require all granted' . "\n";
|
||||||
$php_options_text .= ' AllowOverride All' . "\n";
|
$php_options_text .= ' AllowOverride All' . "\n";
|
||||||
$php_options_text .= ' </Directory>' . "\n";
|
|
||||||
} elseif ($phpconfig['pass_authorizationheader'] == '1') {
|
} elseif ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
// allow Pass of Authorization header
|
// allow Pass of Authorization header
|
||||||
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
|
||||||
$php_options_text .= ' CGIPassAuth On' . "\n";
|
$php_options_text .= ' CGIPassAuth On' . "\n";
|
||||||
$php_options_text .= ' </Directory>' . "\n";
|
|
||||||
}
|
}
|
||||||
|
$php_options_text .= ' </Directory>' . "\n";
|
||||||
} else {
|
} else {
|
||||||
$addheader = "";
|
$addheader = "";
|
||||||
if ($phpconfig['pass_authorizationheader'] == '1') {
|
if ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
@@ -196,6 +195,9 @@ class ApacheFcgi extends Apache
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$php_options_text .= ' FcgidIdleTimeout ' . Settings::Get('system.mod_fcgid_idle_timeout') . "\n";
|
$php_options_text .= ' FcgidIdleTimeout ' . Settings::Get('system.mod_fcgid_idle_timeout') . "\n";
|
||||||
|
if ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
|
$php_options_text .= ' FcgidPassHeader Authorization' . "\n";
|
||||||
|
}
|
||||||
if ((int)Settings::Get('system.mod_fcgid_wrapper') == 0) {
|
if ((int)Settings::Get('system.mod_fcgid_wrapper') == 0) {
|
||||||
$php_options_text .= ' SuexecUserGroup "' . $domain['loginname'] . '" "' . $domain['loginname'] . '"' . "\n";
|
$php_options_text .= ' SuexecUserGroup "' . $domain['loginname'] . '" "' . $domain['loginname'] . '"' . "\n";
|
||||||
$php_options_text .= ' ScriptAlias /php/ ' . $php->getInterface()->getConfigDir() . "\n";
|
$php_options_text .= ' ScriptAlias /php/ ' . $php->getInterface()->getConfigDir() . "\n";
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ class HttpConfigBase
|
|||||||
$froxlor_ssl_settings_stmt = Database::prepare("
|
$froxlor_ssl_settings_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
||||||
WHERE `domainid` = '0' AND
|
WHERE `domainid` = '0' AND
|
||||||
(`expirationdate` < DATE_ADD(NOW(), INTERVAL 30 DAY) OR `expirationdate` IS NULL)
|
(`validtodate` < DATE_ADD(NOW(), INTERVAL 30 DAY) OR `validtodate` IS NULL)
|
||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
if ($froxlor_ssl && !empty($froxlor_ssl['ssl_cert_file'])) {
|
if ($froxlor_ssl && !empty($froxlor_ssl['ssl_cert_file'])) {
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
'letsencrypt_test' => "https://acme-staging-v02.api.letsencrypt.org/directory",
|
'letsencrypt_test' => "https://acme-staging-v02.api.letsencrypt.org/directory",
|
||||||
'buypass' => "https://api.buypass.com/acme/directory",
|
'buypass' => "https://api.buypass.com/acme/directory",
|
||||||
'buypass_test' => "https://api.test4.buypass.no/acme/directory",
|
'buypass_test' => "https://api.test4.buypass.no/acme/directory",
|
||||||
'zerossl' => "https://acme.zerossl.com/v2/DV90"
|
'zerossl' => "https://acme.zerossl.com/v2/DV90",
|
||||||
|
'google' => "https://dv.acme-v02.api.pki.goog/directory",
|
||||||
|
'google_test' => "https://dv.acme-v02.test-api.pki.goog/directory",
|
||||||
];
|
];
|
||||||
public static $no_inserttask = false;
|
public static $no_inserttask = false;
|
||||||
private static $apiserver = "";
|
private static $apiserver = "";
|
||||||
@@ -112,7 +114,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
`ssl_cert_chainfile` = :chain,
|
`ssl_cert_chainfile` = :chain,
|
||||||
`ssl_csr_file` = :csr,
|
`ssl_csr_file` = :csr,
|
||||||
`ssl_fullchain_file` = :fullchain,
|
`ssl_fullchain_file` = :fullchain,
|
||||||
`expirationdate` = :expirationdate
|
`validfromdate` = :validfromdate,
|
||||||
|
`validtodate` = :validtodate,
|
||||||
|
`issuer` = :issuer
|
||||||
");
|
");
|
||||||
|
|
||||||
// prepare domain update sql
|
// prepare domain update sql
|
||||||
@@ -134,7 +138,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
'lepublickey' => Settings::Get('system.lepublickey'),
|
'lepublickey' => Settings::Get('system.lepublickey'),
|
||||||
'leregistered' => Settings::Get('system.leregistered'),
|
'leregistered' => Settings::Get('system.leregistered'),
|
||||||
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
||||||
'expirationdate' => null,
|
'validfromdate' => null,
|
||||||
|
'validtodate' => null,
|
||||||
|
'issuer' => "",
|
||||||
'ssl_cert_file' => null,
|
'ssl_cert_file' => null,
|
||||||
'ssl_key_file' => null,
|
'ssl_key_file' => null,
|
||||||
'ssl_ca_file' => null,
|
'ssl_ca_file' => null,
|
||||||
@@ -169,7 +175,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
'lepublickey' => Settings::Get('system.lepublickey'),
|
'lepublickey' => Settings::Get('system.lepublickey'),
|
||||||
'leregistered' => Settings::Get('system.leregistered'),
|
'leregistered' => Settings::Get('system.leregistered'),
|
||||||
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
||||||
'expirationdate' => is_array($renew_froxlor) ? $renew_froxlor['expirationdate'] : date('Y-m-d H:i:s', 0),
|
'validfromdate' => is_array($renew_froxlor) ? $renew_froxlor['validfromdate'] : date('Y-m-d H:i:s', 0),
|
||||||
|
'validtodate' => is_array($renew_froxlor) ? $renew_froxlor['validtodate'] : date('Y-m-d H:i:s', 0),
|
||||||
|
'issuer' => is_array($renew_froxlor) ? $renew_froxlor['issuer'] : "",
|
||||||
'ssl_cert_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_cert_file'] : null,
|
'ssl_cert_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_cert_file'] : null,
|
||||||
'ssl_key_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_key_file'] : null,
|
'ssl_key_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_key_file'] : null,
|
||||||
'ssl_ca_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_ca_file'] : null,
|
'ssl_ca_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_ca_file'] : null,
|
||||||
@@ -185,7 +193,7 @@ class AcmeSh extends FroxlorCron
|
|||||||
'loginname' => $domain['loginname'],
|
'loginname' => $domain['loginname'],
|
||||||
'adminsession' => 0
|
'adminsession' => 0
|
||||||
]);
|
]);
|
||||||
if (defined('CRON_IS_FORCED') || self::checkFsFilesAreNewer($domain['domain'], $domain['expirationdate'])) {
|
if (defined('CRON_IS_FORCED') || self::checkFsFilesAreNewer($domain['domain'], $domain['validtodate'])) {
|
||||||
self::certToDb($domain, $cronlog, []);
|
self::certToDb($domain, $cronlog, []);
|
||||||
$changedetected = 1;
|
$changedetected = 1;
|
||||||
}
|
}
|
||||||
@@ -219,7 +227,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
// also check for possible existing certificate
|
// also check for possible existing certificate
|
||||||
if (!$froxlor_ssl && !self::checkFsFilesAreNewer(Settings::Get('system.hostname'), date('Y-m-d H:i:s'))) {
|
if (($froxlor_ssl && empty($froxlor_ssl['validtodate']))
|
||||||
|
|| (!$froxlor_ssl && !self::checkFsFilesAreNewer(Settings::Get('system.hostname'), date('Y-m-d H:i:s')))
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,7 +287,9 @@ EOC;
|
|||||||
SELECT
|
SELECT
|
||||||
domssl.`id`,
|
domssl.`id`,
|
||||||
domssl.`domainid`,
|
domssl.`domainid`,
|
||||||
domssl.`expirationdate`,
|
domssl.`validfromdate`,
|
||||||
|
domssl.`validtodate`,
|
||||||
|
domssl.`issuer`,
|
||||||
domssl.`ssl_cert_file`,
|
domssl.`ssl_cert_file`,
|
||||||
domssl.`ssl_key_file`,
|
domssl.`ssl_key_file`,
|
||||||
domssl.`ssl_ca_file`,
|
domssl.`ssl_ca_file`,
|
||||||
@@ -304,7 +316,7 @@ EOC;
|
|||||||
AND dom.`letsencrypt` = 1
|
AND dom.`letsencrypt` = 1
|
||||||
AND dom.`aliasdomain` IS NULL
|
AND dom.`aliasdomain` IS NULL
|
||||||
AND dom.`iswildcarddomain` = 0
|
AND dom.`iswildcarddomain` = 0
|
||||||
AND domssl.`expirationdate` IS NULL
|
AND domssl.`validtodate` IS NULL
|
||||||
");
|
");
|
||||||
$customer_ssl = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
|
$customer_ssl = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
if ($customer_ssl) {
|
if ($customer_ssl) {
|
||||||
@@ -328,7 +340,7 @@ EOC;
|
|||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
// also check for possible existing certificate
|
// also check for possible existing certificate
|
||||||
if ($froxlor_ssl && self::checkFsFilesAreNewer(Settings::Get('system.hostname'), $froxlor_ssl['expirationdate'])) {
|
if ($froxlor_ssl && self::checkFsFilesAreNewer(Settings::Get('system.hostname'), $froxlor_ssl['validtodate'])) {
|
||||||
return $froxlor_ssl;
|
return $froxlor_ssl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,7 +356,9 @@ EOC;
|
|||||||
SELECT
|
SELECT
|
||||||
domssl.`id`,
|
domssl.`id`,
|
||||||
domssl.`domainid`,
|
domssl.`domainid`,
|
||||||
domssl.`expirationdate`,
|
domssl.`validfromdate`,
|
||||||
|
domssl.`validtodate`,
|
||||||
|
domssl.`issuer`,
|
||||||
domssl.`ssl_cert_file`,
|
domssl.`ssl_cert_file`,
|
||||||
domssl.`ssl_key_file`,
|
domssl.`ssl_key_file`,
|
||||||
dom.`domain`,
|
dom.`domain`,
|
||||||
@@ -368,7 +382,7 @@ EOC;
|
|||||||
if ($renew_certs) {
|
if ($renew_certs) {
|
||||||
if ($check) {
|
if ($check) {
|
||||||
foreach ($renew_certs as $cert) {
|
foreach ($renew_certs as $cert) {
|
||||||
if (self::checkFsFilesAreNewer($cert['domain'], $cert['expirationdate'])) {
|
if (self::checkFsFilesAreNewer($cert['domain'], $cert['validtodate'])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -451,7 +465,7 @@ EOC;
|
|||||||
// Only issue let's encrypt certificate if no broken ssl_redirect is enabled
|
// Only issue let's encrypt certificate if no broken ssl_redirect is enabled
|
||||||
if ($certrow['ssl_redirect'] != 2) {
|
if ($certrow['ssl_redirect'] != 2) {
|
||||||
$do_force = false;
|
$do_force = false;
|
||||||
if (!empty($certrow['ssl_cert_file']) && empty($certrow['expirationdate'])) {
|
if (!empty($certrow['ssl_cert_file']) && empty($certrow['validtodate'])) {
|
||||||
// domain changed (SAN or similar)
|
// domain changed (SAN or similar)
|
||||||
$do_force = true;
|
$do_force = true;
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']);
|
||||||
@@ -519,7 +533,7 @@ EOC;
|
|||||||
foreach ($loop_domains as $idx => $domain) {
|
foreach ($loop_domains as $idx => $domain) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Validating DNS of " . $domain);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Validating DNS of " . $domain);
|
||||||
// ips according to NS
|
// ips according to NS
|
||||||
$domain_ips = PhpHelper::gethostbynamel6($domain);
|
$domain_ips = PhpHelper::gethostbynamel6($domain, true, Settings::Get('system.le_domain_dnscheck_resolver'));
|
||||||
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
||||||
// no common ips...
|
// no common ips...
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $domain . " due to no system known IP address via DNS check");
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $domain . " due to no system known IP address via DNS check");
|
||||||
@@ -555,7 +569,7 @@ EOC;
|
|||||||
if (Settings::Get('system.letsencryptreuseold') != '1') {
|
if (Settings::Get('system.letsencryptreuseold') != '1') {
|
||||||
$acmesh_cmd .= " --always-force-new-domain-key";
|
$acmesh_cmd .= " --always-force-new-domain-key";
|
||||||
}
|
}
|
||||||
if (Settings::Get('system.letsencryptca') == 'letsencrypt_test') {
|
if (substr(Settings::Get('system.letsencryptca'), -5) == '_test') {
|
||||||
$acmesh_cmd .= " --staging";
|
$acmesh_cmd .= " --staging";
|
||||||
}
|
}
|
||||||
if ($force) {
|
if ($force) {
|
||||||
@@ -592,7 +606,9 @@ EOC;
|
|||||||
'chain' => $return['chain'],
|
'chain' => $return['chain'],
|
||||||
'csr' => $return['csr'],
|
'csr' => $return['csr'],
|
||||||
'fullchain' => $return['fullchain'],
|
'fullchain' => $return['fullchain'],
|
||||||
'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t'])
|
'validfromdate' => date('Y-m-d H:i:s', $newcert['validFrom_time_t']),
|
||||||
|
'validtodate' => date('Y-m-d H:i:s', $newcert['validTo_time_t']),
|
||||||
|
'issuer' => $newcert['issuer']['O'] ?? ""
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($certrow['ssl_redirect'] == 3) {
|
if ($certrow['ssl_redirect'] == 3) {
|
||||||
|
|||||||
@@ -414,6 +414,8 @@ class Lighttpd extends HttpConfigBase
|
|||||||
$domain['documentroot'] = trim($domain['documentroot']);
|
$domain['documentroot'] = trim($domain['documentroot']);
|
||||||
|
|
||||||
if (preg_match('/^https?\:\/\//', $domain['documentroot'])) {
|
if (preg_match('/^https?\:\/\//', $domain['documentroot'])) {
|
||||||
|
$possible_deactivated_webroot = $this->getWebroot($domain);
|
||||||
|
if ($this->deactivated == false) {
|
||||||
$uri = $domain['documentroot'];
|
$uri = $domain['documentroot'];
|
||||||
|
|
||||||
// Get domain's redirect code
|
// Get domain's redirect code
|
||||||
@@ -423,6 +425,9 @@ class Lighttpd extends HttpConfigBase
|
|||||||
$vhost_content .= ' url.redirect = (' . "\n";
|
$vhost_content .= ' url.redirect = (' . "\n";
|
||||||
$vhost_content .= ' "^/(.*)$" => "' . $uri . '$1"' . "\n";
|
$vhost_content .= ' "^/(.*)$" => "' . $uri . '$1"' . "\n";
|
||||||
$vhost_content .= ' )' . "\n";
|
$vhost_content .= ' )' . "\n";
|
||||||
|
} elseif (Settings::Get('system.deactivateddocroot') != '') {
|
||||||
|
$vhost_content .= $possible_deactivated_webroot;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
FileDir::mkDirWithCorrectOwnership($domain['customerroot'], $domain['documentroot'], $domain['guid'], $domain['guid'], true, true);
|
FileDir::mkDirWithCorrectOwnership($domain['customerroot'], $domain['documentroot'], $domain['guid'], $domain['guid'], true, true);
|
||||||
|
|
||||||
@@ -562,12 +567,12 @@ class Lighttpd extends HttpConfigBase
|
|||||||
return $servernames_text;
|
return $servernames_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getWebroot($domain, $ssl)
|
protected function getWebroot($domain, bool $ssl = false)
|
||||||
{
|
{
|
||||||
$webroot_text = '';
|
$webroot_text = '';
|
||||||
|
|
||||||
if ($domain['deactivated'] == '1' && Settings::Get('system.deactivateddocroot') != '') {
|
if (($domain['deactivated'] == '1' || $domain['customer_deactivated'] == '1') && Settings::Get('system.deactivateddocroot') != '') {
|
||||||
$webroot_text .= ' # Using docroot for deactivated users...' . "\n";
|
$webroot_text .= ' # Using docroot for deactivated users/domains...' . "\n";
|
||||||
$webroot_text .= ' server.document-root = "' . FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')) . "\"\n";
|
$webroot_text .= ' server.document-root = "' . FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')) . "\"\n";
|
||||||
$this->deactivated = true;
|
$this->deactivated = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -719,6 +724,10 @@ class Lighttpd extends HttpConfigBase
|
|||||||
|
|
||||||
$statTool = Settings::Get('system.traffictool');
|
$statTool = Settings::Get('system.traffictool');
|
||||||
$statDomain = "";
|
$statDomain = "";
|
||||||
|
if ($statTool == 'awstats') {
|
||||||
|
// awstats generates for each domain regardless of speciallogfile
|
||||||
|
$statDomain = "/" . $domain['domain'];
|
||||||
|
}
|
||||||
if ($domain['speciallogfile'] == '1') {
|
if ($domain['speciallogfile'] == '1') {
|
||||||
$statDomain = "/" . (($domain['parentdomainid'] == '0') ? $domain['domain'] : $domain['parentdomain']);
|
$statDomain = "/" . (($domain['parentdomainid'] == '0') ? $domain['domain'] : $domain['parentdomain']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -493,10 +493,10 @@ class Nginx extends HttpConfigBase
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// check whether the customer is deactivated and NO docroot for deactivated users has been set#
|
// check whether the customer/domain is deactivated and NO docroot for deactivated users has been set#
|
||||||
$ddr = Settings::Get('system.deactivateddocroot');
|
$ddr = Settings::Get('system.deactivateddocroot');
|
||||||
if ($domain['deactivated'] == '1' && empty($ddr)) {
|
if (($domain['deactivated'] == '1' || $domain['customer_deactivated'] == '1') && empty($ddr)) {
|
||||||
return '# Customer deactivated and a docroot for deactivated users hasn\'t been set.' . "\n";
|
return '# Customer deactivated and a docroot for deactivated users/domains hasn\'t been set.' . "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
$vhost_content = '';
|
$vhost_content = '';
|
||||||
@@ -596,6 +596,8 @@ class Nginx extends HttpConfigBase
|
|||||||
|
|
||||||
// if the documentroot is an URL we just redirect
|
// if the documentroot is an URL we just redirect
|
||||||
if (preg_match('/^https?\:\/\//', $domain['documentroot'])) {
|
if (preg_match('/^https?\:\/\//', $domain['documentroot'])) {
|
||||||
|
$possible_deactivated_webroot = $this->getWebroot($domain);
|
||||||
|
if ($this->deactivated == false) {
|
||||||
$uri = $domain['documentroot'];
|
$uri = $domain['documentroot'];
|
||||||
if (substr($uri, -1) == '/') {
|
if (substr($uri, -1) == '/') {
|
||||||
$uri = substr($uri, 0, -1);
|
$uri = substr($uri, 0, -1);
|
||||||
@@ -607,11 +609,14 @@ class Nginx extends HttpConfigBase
|
|||||||
$vhost_content .= "\t" . 'location / {' . "\n";
|
$vhost_content .= "\t" . 'location / {' . "\n";
|
||||||
$vhost_content .= "\t\t" . 'return ' . $code . ' ' . $uri . '$request_uri;' . "\n";
|
$vhost_content .= "\t\t" . 'return ' . $code . ' ' . $uri . '$request_uri;' . "\n";
|
||||||
$vhost_content .= "\t" . '}' . "\n";
|
$vhost_content .= "\t" . '}' . "\n";
|
||||||
|
} elseif (Settings::Get('system.deactivateddocroot') != '') {
|
||||||
|
$vhost_content .= $possible_deactivated_webroot;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
FileDir::mkDirWithCorrectOwnership($domain['customerroot'], $domain['documentroot'], $domain['guid'], $domain['guid'], true);
|
FileDir::mkDirWithCorrectOwnership($domain['customerroot'], $domain['documentroot'], $domain['guid'], $domain['guid'], true);
|
||||||
|
|
||||||
$vhost_content .= $this->getLogFiles($domain);
|
$vhost_content .= $this->getLogFiles($domain);
|
||||||
$vhost_content .= $this->getWebroot($domain, $ssl_vhost);
|
$vhost_content .= $this->getWebroot($domain);
|
||||||
|
|
||||||
if ($this->deactivated == false) {
|
if ($this->deactivated == false) {
|
||||||
$vhost_content = $this->mergeVhostCustom($vhost_content, $this->createPathOptions($domain)) . "\n";
|
$vhost_content = $this->mergeVhostCustom($vhost_content, $this->createPathOptions($domain)) . "\n";
|
||||||
@@ -770,12 +775,12 @@ class Nginx extends HttpConfigBase
|
|||||||
return $logfiles_text;
|
return $logfiles_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getWebroot($domain, $ssl)
|
protected function getWebroot($domain)
|
||||||
{
|
{
|
||||||
$webroot_text = '';
|
$webroot_text = '';
|
||||||
|
|
||||||
if ($domain['deactivated'] == '1' && Settings::Get('system.deactivateddocroot') != '') {
|
if (($domain['deactivated'] == '1' || $domain['customer_deactivated'] == '1' ) && Settings::Get('system.deactivateddocroot') != '') {
|
||||||
$webroot_text .= "\t" . '# Using docroot for deactivated users...' . "\n";
|
$webroot_text .= "\t" . '# Using docroot for deactivated users/domains...' . "\n";
|
||||||
$webroot_text .= "\t" . 'root ' . FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')) . ';' . "\n";
|
$webroot_text .= "\t" . 'root ' . FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')) . ';' . "\n";
|
||||||
$this->deactivated = true;
|
$this->deactivated = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -1035,6 +1040,11 @@ class Nginx extends HttpConfigBase
|
|||||||
$path_options .= "\t\t" . 'auth_basic_user_file ' . FileDir::makeCorrectFile($single['usrf']) . ';' . "\n";
|
$path_options .= "\t\t" . 'auth_basic_user_file ' . FileDir::makeCorrectFile($single['usrf']) . ';' . "\n";
|
||||||
if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') {
|
if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') {
|
||||||
$path_options .= "\t\t" . 'index index.php index.html index.htm;' . "\n";
|
$path_options .= "\t\t" . 'index index.php index.html index.htm;' . "\n";
|
||||||
|
if ($domain['notryfiles'] != 1) {
|
||||||
|
$path_options .= "\t\t" . 'location ~ ^(.+?\.php)(/.*)?$ {' . "\n";
|
||||||
|
$path_options .= "\t\t\t" . 'try_files ' . $domain['nonexistinguri'] . ' @php;' . "\n";
|
||||||
|
$path_options .= "\t\t" . '}' . "\n\n";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$path_options .= "\t\t" . 'index index.html index.htm;' . "\n";
|
$path_options .= "\t\t" . 'index index.html index.htm;' . "\n";
|
||||||
}
|
}
|
||||||
@@ -1120,6 +1130,10 @@ class Nginx extends HttpConfigBase
|
|||||||
|
|
||||||
$statTool = Settings::Get('system.traffictool');
|
$statTool = Settings::Get('system.traffictool');
|
||||||
$statDomain = "";
|
$statDomain = "";
|
||||||
|
if ($statTool == 'awstats') {
|
||||||
|
// awstats generates for each domain regardless of speciallogfile
|
||||||
|
$statDomain = "/" . $domain['domain'];
|
||||||
|
}
|
||||||
if ($domain['speciallogfile'] == '1') {
|
if ($domain['speciallogfile'] == '1') {
|
||||||
$statDomain = "/" . (($domain['parentdomainid'] == '0') ? $domain['domain'] : $domain['parentdomain']);
|
$statDomain = "/" . (($domain['parentdomainid'] == '0') ? $domain['domain'] : $domain['parentdomain']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -342,8 +342,17 @@ pm.max_children = 1
|
|||||||
public function getSocketFile($createifnotexists = true)
|
public function getSocketFile($createifnotexists = true)
|
||||||
{
|
{
|
||||||
$socketdir = FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir'));
|
$socketdir = FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir'));
|
||||||
// add fpm-config-id to filename so it's unique for the fpm-daemon and doesn't interfere with running configs when reuilding
|
// add fpm-config-id to filename, so it's unique for the fpm-daemon and doesn't interfere with running configs when reuilding
|
||||||
$socket = strtolower(FileDir::makeCorrectFile($socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['loginname'] . '-' . $this->domain['domain'] . '-php-fpm.socket'));
|
$socket_filename = $socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['loginname'] . '-' . $this->domain['domain'] . '-php-fpm.socket';
|
||||||
|
if (strlen($socket_filename) > 100) {
|
||||||
|
// respect the unix socket-length limitation
|
||||||
|
$socket_filename = $socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['loginname'] . '-' . $this->domain['id'] . '-php-fpm.socket';
|
||||||
|
if (strlen($socket_filename) > 100) {
|
||||||
|
// even a long loginname it seems
|
||||||
|
$socket_filename = $socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['guid'] . '-' . $this->domain['id'] . '-php-fpm.socket';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$socket = strtolower(FileDir::makeCorrectFile($socket_filename));
|
||||||
|
|
||||||
if (!is_dir($socketdir) && $createifnotexists) {
|
if (!is_dir($socketdir) && $createifnotexists) {
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg($socketdir));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($socketdir));
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class WebserverBase
|
|||||||
{
|
{
|
||||||
$query = "SELECT `d`.*, `pd`.`domain` AS `parentdomain`, `c`.`loginname`,
|
$query = "SELECT `d`.*, `pd`.`domain` AS `parentdomain`, `c`.`loginname`,
|
||||||
`d`.`phpsettingid`, `c`.`adminid`, `c`.`guid`, `c`.`email`,
|
`d`.`phpsettingid`, `c`.`adminid`, `c`.`guid`, `c`.`email`,
|
||||||
`c`.`documentroot` AS `customerroot`, `c`.`deactivated`,
|
`c`.`documentroot` AS `customerroot`, `c`.`deactivated` as `customer_deactivated`,
|
||||||
`c`.`phpenabled` AS `phpenabled_customer`,
|
`c`.`phpenabled` AS `phpenabled_customer`,
|
||||||
`d`.`phpenabled` AS `phpenabled_vhost`
|
`d`.`phpenabled` AS `phpenabled_vhost`
|
||||||
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
||||||
|
|||||||
@@ -146,28 +146,37 @@ class BackupCron extends FroxlorCron
|
|||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
|
||||||
|
|
||||||
// get all customer database-names
|
// get all customer database-names
|
||||||
$sel_stmt = Database::prepare("SELECT `databasename` FROM `" . TABLE_PANEL_DATABASES . "` WHERE `customerid` = :cid");
|
$sel_stmt = Database::prepare("SELECT `databasename`, `dbserver` FROM `" . TABLE_PANEL_DATABASES . "` WHERE `customerid` = :cid ORDER BY `dbserver`");
|
||||||
Database::pexecute($sel_stmt, [
|
Database::pexecute($sel_stmt, [
|
||||||
'cid' => $data['customerid']
|
'cid' => $data['customerid']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Database::needRoot(true);
|
$has_dbs = false;
|
||||||
|
$current_dbserver = null;
|
||||||
|
while ($row = $sel_stmt->fetch()) {
|
||||||
|
// Get sql_root data for the specific database-server the database resides on
|
||||||
|
if ($current_dbserver != $row['dbserver']) {
|
||||||
|
Database::needRoot(true, $row['dbserver']);
|
||||||
Database::needSqlData();
|
Database::needSqlData();
|
||||||
$sql_root = Database::getSqlData();
|
$sql_root = Database::getSqlData();
|
||||||
Database::needRoot(false);
|
Database::needRoot(false);
|
||||||
|
// create temporary mysql-defaults file for the connection-credentials/details
|
||||||
$mysqlcnf_file = tempnam("/tmp", "frx");
|
$mysqlcnf_file = tempnam("/tmp", "frx");
|
||||||
$mysqlcnf = "[mysqldump]\npassword=".$sql_root['passwd']."\n";
|
$mysqlcnf = "[mysqldump]\npassword=" . $sql_root['passwd'] . "\nhost=" . $sql_root['host'] . "\n";
|
||||||
|
if (!empty($sql_root['port'])) {
|
||||||
|
$mysqlcnf .= "port=" . $sql_root['port'] . "\n";
|
||||||
|
} elseif (!empty($sql_root['socket'])) {
|
||||||
|
$mysqlcnf .= "socket=" . $sql_root['socket'] . "\n";
|
||||||
|
}
|
||||||
file_put_contents($mysqlcnf_file, $mysqlcnf);
|
file_put_contents($mysqlcnf_file, $mysqlcnf);
|
||||||
|
}
|
||||||
$has_dbs = false;
|
|
||||||
while ($row = $sel_stmt->fetch()) {
|
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mysqldump -u ' . escapeshellarg($sql_root['user']) . ' -pXXXXX ' . $row['databasename'] . ' > ' . FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mysqldump -u ' . escapeshellarg($sql_root['user']) . ' -pXXXXX ' . $row['databasename'] . ' > ' . FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'));
|
||||||
$bool_false = false;
|
$bool_false = false;
|
||||||
FileDir::safe_exec('mysqldump --defaults-file=' . escapeshellarg($mysqlcnf_file) . ' -u ' . escapeshellarg($sql_root['user']) . ' ' . $row['databasename'] . ' > ' . FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'), $bool_false, [
|
FileDir::safe_exec('mysqldump --defaults-file=' . escapeshellarg($mysqlcnf_file) . ' -u ' . escapeshellarg($sql_root['user']) . ' ' . $row['databasename'] . ' > ' . FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'), $bool_false, [
|
||||||
'>'
|
'>'
|
||||||
]);
|
]);
|
||||||
$has_dbs = true;
|
$has_dbs = true;
|
||||||
|
$current_dbserver = $row['dbserver'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($has_dbs) {
|
if ($has_dbs) {
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ namespace Froxlor\Cron\Traffic;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Froxlor\Cron\FroxlorCron;
|
use Froxlor\Cron\FroxlorCron;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FileDir;
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\PhpHelper;
|
use Froxlor\PhpHelper;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
@@ -99,8 +97,8 @@ class ReportsCron extends FroxlorCron
|
|||||||
'COMPANY' => $rep_userinfo['company'],
|
'COMPANY' => $rep_userinfo['company'],
|
||||||
'USERNAME' => $rep_userinfo['loginname'],
|
'USERNAME' => $rep_userinfo['loginname'],
|
||||||
'CUSTOMER_NO' => $rep_userinfo['customernumber'],
|
'CUSTOMER_NO' => $rep_userinfo['customernumber'],
|
||||||
'TRAFFIC' => PhpHelper::sizeReadable($row['traffic'], null, 'bi'),
|
'TRAFFIC' => PhpHelper::sizeReadable((int)$row['traffic'], null, 'bi'),
|
||||||
'TRAFFICUSED' => PhpHelper::sizeReadable($row['traffic_used'], null, 'bi'),
|
'TRAFFICUSED' => PhpHelper::sizeReadable((int)$row['traffic_used'], null, 'bi'),
|
||||||
'USAGE_PERCENT' => round(($row['traffic_used'] * 100) / $row['traffic'], 2),
|
'USAGE_PERCENT' => round(($row['traffic_used'] * 100) / $row['traffic'], 2),
|
||||||
'MAX_PERCENT' => Settings::Get('system.report_trafficmax')
|
'MAX_PERCENT' => Settings::Get('system.report_trafficmax')
|
||||||
];
|
];
|
||||||
@@ -182,8 +180,8 @@ class ReportsCron extends FroxlorCron
|
|||||||
if (isset($row['traffic']) && $row['traffic'] > 0 && (($row['traffic_used_total'] * 100) / ($row['traffic'])) >= (int)Settings::Get('system.report_trafficmax')) {
|
if (isset($row['traffic']) && $row['traffic'] > 0 && (($row['traffic_used_total'] * 100) / ($row['traffic'])) >= (int)Settings::Get('system.report_trafficmax')) {
|
||||||
$replace_arr = [
|
$replace_arr = [
|
||||||
'NAME' => $row['name'],
|
'NAME' => $row['name'],
|
||||||
'TRAFFIC' => PhpHelper::sizeReadable($row['traffic'], null, 'bi'),
|
'TRAFFIC' => PhpHelper::sizeReadable((int)$row['traffic'], null, 'bi'),
|
||||||
'TRAFFICUSED' => PhpHelper::sizeReadable($row['traffic_used_total'], null, 'bi'),
|
'TRAFFICUSED' => PhpHelper::sizeReadable((int)$row['traffic_used_total'], null, 'bi'),
|
||||||
'USAGE_PERCENT' => round(($row['traffic_used_total'] * 100) / $row['traffic'], 2),
|
'USAGE_PERCENT' => round(($row['traffic_used_total'] * 100) / $row['traffic'], 2),
|
||||||
'MAX_PERCENT' => Settings::Get('system.report_trafficmax')
|
'MAX_PERCENT' => Settings::Get('system.report_trafficmax')
|
||||||
];
|
];
|
||||||
@@ -265,10 +263,10 @@ class ReportsCron extends FroxlorCron
|
|||||||
|
|
||||||
while ($customer = $customers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($customer = $customers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$customer['traffic'] *= 1024;
|
$customer['traffic'] *= 1024;
|
||||||
$t = $customer['traffic_used_total'] * 1024;
|
$t = (int) $customer['traffic_used_total'] * 1024;
|
||||||
if ($customer['traffic'] > 0) {
|
if ($customer['traffic'] > 0) {
|
||||||
$p = (($t * 100) / $customer['traffic']);
|
$p = (($t * 100) / $customer['traffic']);
|
||||||
$tg = $customer['traffic'];
|
$tg = (int) $customer['traffic'];
|
||||||
$str = sprintf('%s ( %00.1f %% )', PhpHelper::sizeReadable($t, null, 'bi'), $p);
|
$str = sprintf('%s ( %00.1f %% )', PhpHelper::sizeReadable($t, null, 'bi'), $p);
|
||||||
$mail_body .= sprintf('%-15s', $customer['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . sprintf('%s', PhpHelper::sizeReadable($tg, null, 'bi')) . "\n";
|
$mail_body .= sprintf('%-15s', $customer['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . sprintf('%s', PhpHelper::sizeReadable($tg, null, 'bi')) . "\n";
|
||||||
} elseif ($customer['traffic'] == 0) {
|
} elseif ($customer['traffic'] == 0) {
|
||||||
@@ -282,10 +280,10 @@ class ReportsCron extends FroxlorCron
|
|||||||
|
|
||||||
$mail_body .= '---------------------------------------------------------------' . "\n";
|
$mail_body .= '---------------------------------------------------------------' . "\n";
|
||||||
|
|
||||||
$t = $row['traffic_used_total'];
|
$t = (int) $row['traffic_used_total'];
|
||||||
if ($row['traffic'] > 0) {
|
if ($row['traffic'] > 0) {
|
||||||
$p = (($t * 100) / $row['traffic']);
|
$p = (($t * 100) / $row['traffic']);
|
||||||
$tg = $row['traffic'];
|
$tg = (int) $row['traffic'];
|
||||||
$str = sprintf('%s ( %00.1f %% )', PhpHelper::sizeReadable($t, null, 'bi'), $p);
|
$str = sprintf('%s ( %00.1f %% )', PhpHelper::sizeReadable($t, null, 'bi'), $p);
|
||||||
$mail_body .= sprintf('%-15s', $row['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . sprintf('%s', PhpHelper::sizeReadable($tg, null, 'bi')) . "\n";
|
$mail_body .= sprintf('%-15s', $row['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . sprintf('%s', PhpHelper::sizeReadable($tg, null, 'bi')) . "\n";
|
||||||
} elseif ($row['traffic'] == 0) {
|
} elseif ($row['traffic'] == 0) {
|
||||||
@@ -369,8 +367,8 @@ class ReportsCron extends FroxlorCron
|
|||||||
'COMPANY' => $rep_userinfo['company'],
|
'COMPANY' => $rep_userinfo['company'],
|
||||||
'USERNAME' => $rep_userinfo['loginname'],
|
'USERNAME' => $rep_userinfo['loginname'],
|
||||||
'CUSTOMER_NO' => $rep_userinfo['customernumber'],
|
'CUSTOMER_NO' => $rep_userinfo['customernumber'],
|
||||||
'DISKAVAILABLE' => PhpHelper::sizeReadable($row['diskspace'], null, 'bi'),
|
'DISKAVAILABLE' => PhpHelper::sizeReadable((int)$row['diskspace'], null, 'bi'),
|
||||||
'DISKUSED' => PhpHelper::sizeReadable($row['diskspace_used'], null, 'bi'),
|
'DISKUSED' => PhpHelper::sizeReadable((int)$row['diskspace_used'], null, 'bi'),
|
||||||
'USAGE_PERCENT' => round(($row['diskspace_used'] * 100) / $row['diskspace'], 2),
|
'USAGE_PERCENT' => round(($row['diskspace_used'] * 100) / $row['diskspace'], 2),
|
||||||
'MAX_PERCENT' => Settings::Get('system.report_webmax')
|
'MAX_PERCENT' => Settings::Get('system.report_webmax')
|
||||||
];
|
];
|
||||||
@@ -443,8 +441,8 @@ class ReportsCron extends FroxlorCron
|
|||||||
if (isset($row['diskspace']) && $row['diskspace_used'] != null && $row['diskspace_used'] > 0 && (($row['diskspace_used'] * 100) / $row['diskspace']) >= (int)Settings::Get('system.report_webmax')) {
|
if (isset($row['diskspace']) && $row['diskspace_used'] != null && $row['diskspace_used'] > 0 && (($row['diskspace_used'] * 100) / $row['diskspace']) >= (int)Settings::Get('system.report_webmax')) {
|
||||||
$replace_arr = [
|
$replace_arr = [
|
||||||
'NAME' => $row['name'],
|
'NAME' => $row['name'],
|
||||||
'DISKAVAILABLE' => PhpHelper::sizeReadable($row['diskspace'], null, 'bi'),
|
'DISKAVAILABLE' => PhpHelper::sizeReadable((int)$row['diskspace'], null, 'bi'),
|
||||||
'DISKUSED' => PhpHelper::sizeReadable($row['diskspace_used'], null, 'bi'),
|
'DISKUSED' => PhpHelper::sizeReadable((int)$row['diskspace_used'], null, 'bi'),
|
||||||
'USAGE_PERCENT' => ($row['diskspace_used'] * 100) / $row['diskspace'],
|
'USAGE_PERCENT' => ($row['diskspace_used'] * 100) / $row['diskspace'],
|
||||||
'MAX_PERCENT' => Settings::Get('system.report_webmax')
|
'MAX_PERCENT' => Settings::Get('system.report_webmax')
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ class TrafficCron extends FroxlorCron
|
|||||||
|
|
||||||
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']) {
|
||||||
Database::needRoot(true, $row_database['dbserver']);
|
Database::needRoot(true, $row_database['dbserver'], true);
|
||||||
$last_dbserver = $row_database['dbserver'];
|
$last_dbserver = $row_database['dbserver'];
|
||||||
|
|
||||||
$databases_list = [];
|
$databases_list = [];
|
||||||
@@ -406,7 +406,7 @@ class TrafficCron extends FroxlorCron
|
|||||||
} else {
|
} else {
|
||||||
// Use the old fashioned way with "du"
|
// Use the old fashioned way with "du"
|
||||||
if (file_exists($row['documentroot']) && is_dir($row['documentroot'])) {
|
if (file_exists($row['documentroot']) && is_dir($row['documentroot'])) {
|
||||||
$back = FileDir::safe_exec('du -sk ' . escapeshellarg($row['documentroot']) . '');
|
$back = FileDir::safe_exec('du -sk ' . escapeshellarg($row['documentroot']));
|
||||||
foreach ($back as $backrow) {
|
foreach ($back as $backrow) {
|
||||||
$webspaceusage = explode(' ', $backrow);
|
$webspaceusage = explode(' ', $backrow);
|
||||||
}
|
}
|
||||||
@@ -426,7 +426,7 @@ class TrafficCron extends FroxlorCron
|
|||||||
|
|
||||||
$maildir = FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . $row['loginname']);
|
$maildir = FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . $row['loginname']);
|
||||||
if (file_exists($maildir) && is_dir($maildir)) {
|
if (file_exists($maildir) && is_dir($maildir)) {
|
||||||
$back = FileDir::safe_exec('du -sk ' . escapeshellarg($maildir) . '');
|
$back = FileDir::safe_exec('du -sk ' . escapeshellarg($maildir));
|
||||||
foreach ($back as $backrow) {
|
foreach ($back as $backrow) {
|
||||||
$emailusage = explode(' ', $backrow);
|
$emailusage = explode(' ', $backrow);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,9 +63,10 @@ class CurrentUser
|
|||||||
/**
|
/**
|
||||||
* re-read in the user data if a valid session exists
|
* re-read in the user data if a valid session exists
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function reReadUserData()
|
public static function reReadUserData(): bool
|
||||||
{
|
{
|
||||||
$table = self::isAdmin() ? TABLE_PANEL_ADMINS : TABLE_PANEL_CUSTOMERS;
|
$table = self::isAdmin() ? TABLE_PANEL_ADMINS : TABLE_PANEL_CUSTOMERS;
|
||||||
$userinfo_stmt = Database::prepare("
|
$userinfo_stmt = Database::prepare("
|
||||||
@@ -75,7 +76,7 @@ class CurrentUser
|
|||||||
"loginname" => self::getField('loginname')
|
"loginname" => self::getField('loginname')
|
||||||
]);
|
]);
|
||||||
if ($userinfo) {
|
if ($userinfo) {
|
||||||
// dont just set the data, we need to merge with current data
|
// don't just set the data, we need to merge with current data
|
||||||
// array_merge is a right-reduction - value existing in getData() will be overwritten with $userinfo,
|
// array_merge is a right-reduction - value existing in getData() will be overwritten with $userinfo,
|
||||||
// other than the union-operator (+) which would keep the values already existing from getData()
|
// other than the union-operator (+) which would keep the values already existing from getData()
|
||||||
$newuserinfo = array_merge(self::getData(), $userinfo);
|
$newuserinfo = array_merge(self::getData(), $userinfo);
|
||||||
@@ -107,7 +108,7 @@ class CurrentUser
|
|||||||
*/
|
*/
|
||||||
public static function getField(string $index)
|
public static function getField(string $index)
|
||||||
{
|
{
|
||||||
return isset($_SESSION['userinfo'][$index]) ? $_SESSION['userinfo'][$index] : "";
|
return $_SESSION['userinfo'][$index] ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,6 +131,11 @@ class CurrentUser
|
|||||||
$_SESSION['userinfo'] = $data;
|
$_SESSION['userinfo'] = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $resource
|
||||||
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
public static function canAddResource(string $resource): bool
|
public static function canAddResource(string $resource): bool
|
||||||
{
|
{
|
||||||
$addition = true;
|
$addition = true;
|
||||||
@@ -145,7 +151,8 @@ class CurrentUser
|
|||||||
]);
|
]);
|
||||||
$addition = $result['emaildomains'] != 0;
|
$addition = $result['emaildomains'] != 0;
|
||||||
} elseif ($resource == 'subdomains') {
|
} elseif ($resource == 'subdomains') {
|
||||||
$parentDomainCollection = (new Collection(SubDomains::class, $_SESSION['userinfo'], ['sql_search' => ['d.parentdomainid' => 0]]));
|
$parentDomainCollection = (new Collection(SubDomains::class, $_SESSION['userinfo'],
|
||||||
|
['sql_search' => ['d.parentdomainid' => 0]]));
|
||||||
$addition = $parentDomainCollection != 0;
|
$addition = $parentDomainCollection != 0;
|
||||||
} elseif ($resource == 'domains') {
|
} elseif ($resource == 'domains') {
|
||||||
$customerCollection = (new Collection(Customers::class, $_SESSION['userinfo']));
|
$customerCollection = (new Collection(Customers::class, $_SESSION['userinfo']));
|
||||||
|
|||||||
@@ -31,7 +31,15 @@ use PDO;
|
|||||||
class Customer
|
class Customer
|
||||||
{
|
{
|
||||||
|
|
||||||
public static function getCustomerDetail($customerid, $varname)
|
/**
|
||||||
|
* Get value of a a specific field from a given customer
|
||||||
|
*
|
||||||
|
* @param int $customerid
|
||||||
|
* @param string $varname
|
||||||
|
* @return false|mixed
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function getCustomerDetail(int $customerid, string $varname)
|
||||||
{
|
{
|
||||||
$customer_stmt = Database::prepare("
|
$customer_stmt = Database::prepare("
|
||||||
SELECT `" . $varname . "` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `customerid` = :customerid
|
SELECT `" . $varname . "` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `customerid` = :customerid
|
||||||
@@ -42,20 +50,19 @@ class Customer
|
|||||||
|
|
||||||
if (isset($customer[$varname])) {
|
if (isset($customer[$varname])) {
|
||||||
return $customer[$varname];
|
return $customer[$varname];
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the loginname of a customer by given uid
|
* returns the loginname of a customer by given uid
|
||||||
*
|
*
|
||||||
* @param int $uid
|
* @param int $uid uid of customer
|
||||||
* uid of customer
|
|
||||||
*
|
*
|
||||||
* @return string customers loginname
|
* @return string customers loginname
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function getLoginNameByUid($uid = null)
|
public static function getLoginNameByUid(int $uid)
|
||||||
{
|
{
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT `loginname` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `guid` = :guid
|
SELECT `loginname` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `guid` = :guid
|
||||||
@@ -64,7 +71,7 @@ class Customer
|
|||||||
'guid' => $uid
|
'guid' => $uid
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (is_array($result) && isset($result['loginname'])) {
|
if ($result && isset($result['loginname'])) {
|
||||||
return $result['loginname'];
|
return $result['loginname'];
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -76,23 +83,22 @@ class Customer
|
|||||||
* returns true or false whether perl is
|
* returns true or false whether perl is
|
||||||
* enabled for the given customer
|
* enabled for the given customer
|
||||||
*
|
*
|
||||||
* @param
|
* @param int $cid customer-id
|
||||||
* int customer-id
|
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function customerHasPerlEnabled($cid = 0)
|
public static function customerHasPerlEnabled(int $cid = 0)
|
||||||
{
|
{
|
||||||
if ($cid > 0) {
|
if ($cid > 0) {
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT `perlenabled` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `customerid` = :cid");
|
SELECT `perlenabled` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `customerid` = :cid");
|
||||||
Database::pexecute($result_stmt, [
|
$result = Database::pexecute_first($result_stmt, [
|
||||||
'cid' => $cid
|
'cid' => $cid
|
||||||
]);
|
]);
|
||||||
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
if (is_array($result) && isset($result['perlenabled'])) {
|
if ($result && isset($result['perlenabled'])) {
|
||||||
return $result['perlenabled'] == '1';
|
return (bool)$result['perlenabled'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace Froxlor\Database;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\PhpHelper;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use PDO;
|
use PDO;
|
||||||
@@ -60,39 +61,43 @@ class Database
|
|||||||
/**
|
/**
|
||||||
* indicator whether to use root-connection or not
|
* indicator whether to use root-connection or not
|
||||||
*/
|
*/
|
||||||
private static $needroot = false;
|
private static bool $needroot = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* indicator which database-server we're on (not really used)
|
* indicator which database-server we're on (not really used)
|
||||||
*/
|
*/
|
||||||
private static $dbserver = 0;
|
private static int $dbserver = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* used database-name
|
* used database-name
|
||||||
*/
|
*/
|
||||||
private static $dbname = null;
|
private static ?string $dbname = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sql-access data
|
* sql-access data
|
||||||
*/
|
*/
|
||||||
private static $needsqldata = false;
|
private static bool $needsqldata = false;
|
||||||
|
|
||||||
private static $sqldata = null;
|
private static $sqldata = null;
|
||||||
|
|
||||||
|
private static bool $need_dbname = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for PDOStatement::execute so we can catch the PDOException
|
* Wrapper for PDOStatement::execute, so we can catch the PDOException
|
||||||
* and display the error nicely on the panel - also fetches the
|
* and display the error nicely on the panel - also fetches the
|
||||||
* result from the statement and returns the resulting array
|
* result from the statement and returns the resulting array
|
||||||
*
|
*
|
||||||
* @param PDOStatement $stmt
|
* @param PDOStatement $stmt
|
||||||
* @param array $params
|
* @param array|null $params
|
||||||
* (optional)
|
* (optional)
|
||||||
* @param bool $showerror
|
* @param bool $showerror
|
||||||
* suppress error display (default true)
|
* suppress error display (default true)
|
||||||
|
* @param bool $json_response
|
||||||
*
|
*
|
||||||
* @return array
|
* @return mixed
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function pexecute_first(&$stmt, $params = null, $showerror = true, $json_response = false)
|
public static function pexecute_first(PDOStatement &$stmt, $params = null, bool $showerror = true, bool $json_response = false)
|
||||||
{
|
{
|
||||||
self::pexecute($stmt, $params, $showerror, $json_response);
|
self::pexecute($stmt, $params, $showerror, $json_response);
|
||||||
return $stmt->fetch(PDO::FETCH_ASSOC);
|
return $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
@@ -103,12 +108,15 @@ class Database
|
|||||||
* and display the error nicely on the panel
|
* and display the error nicely on the panel
|
||||||
*
|
*
|
||||||
* @param PDOStatement $stmt
|
* @param PDOStatement $stmt
|
||||||
* @param array $params
|
* @param array|null $params
|
||||||
* (optional)
|
* (optional)
|
||||||
* @param bool $showerror
|
* @param bool $showerror
|
||||||
* suppress error display (default true)
|
* suppress error display (default true)
|
||||||
|
* @param bool $json_response
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function pexecute(&$stmt, $params = null, $showerror = true, $json_response = false)
|
public static function pexecute(PDOStatement &$stmt, $params = null, bool $showerror = true, bool $json_response = false)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$stmt->execute($params);
|
$stmt->execute($params);
|
||||||
@@ -122,9 +130,10 @@ class Database
|
|||||||
*
|
*
|
||||||
* @param PDOException $error
|
* @param PDOException $error
|
||||||
* @param bool $showerror
|
* @param bool $showerror
|
||||||
* if set to false, the error will be logged but we go on
|
* if set to false, the error will be logged, but we go on
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private static function showerror($error, $showerror = true, $json_response = false, PDOStatement $stmt = null)
|
private static function showerror(Exception $error, bool $showerror = true, bool $json_response = false, PDOStatement $stmt = null)
|
||||||
{
|
{
|
||||||
global $userinfo, $theme, $linker;
|
global $userinfo, $theme, $linker;
|
||||||
|
|
||||||
@@ -135,22 +144,30 @@ class Database
|
|||||||
require Froxlor::getInstallDir() . "/lib/userdata.inc.php";
|
require Froxlor::getInstallDir() . "/lib/userdata.inc.php";
|
||||||
|
|
||||||
// le format
|
// le format
|
||||||
if (isset($sql['root_user']) && isset($sql['root_password']) && !is_array($sql_root)) {
|
if (isset($sql['root_user']) && isset($sql['root_password']) && empty($sql_root)) {
|
||||||
$sql_root = [
|
$sql_root = [
|
||||||
0 => [
|
0 => [
|
||||||
'caption' => 'Default',
|
'caption' => 'Default',
|
||||||
'host' => $sql['host'],
|
'host' => $sql['host'],
|
||||||
'socket' => (isset($sql['socket']) ? $sql['socket'] : null),
|
'socket' => ($sql['socket'] ?? null),
|
||||||
'user' => $sql['root_user'],
|
'user' => $sql['root_user'],
|
||||||
'password' => $sql['root_password']
|
'password' => $sql['root_password']
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
unset($sql['root_user']);
|
||||||
|
unset($sql['root_password']);
|
||||||
|
// write new layout so this won't happen again
|
||||||
|
self::generateNewUserData($sql, $sql_root);
|
||||||
|
// re-read file
|
||||||
|
require Froxlor::getInstallDir() . "/lib/userdata.inc.php";
|
||||||
}
|
}
|
||||||
|
|
||||||
$substitutions = [
|
$substitutions = [
|
||||||
$sql['password'] => 'DB_UNPRIV_PWD',
|
$sql['password'] => 'DB_UNPRIV_PWD',
|
||||||
$sql_root[0]['password'] => 'DB_ROOT_PWD'
|
|
||||||
];
|
];
|
||||||
|
foreach ($sql_root as $sql_root_data) {
|
||||||
|
$substitutions[$sql_root_data['password']] = 'DB_ROOT_PWD';
|
||||||
|
}
|
||||||
|
|
||||||
// hide username/password in messages
|
// hide username/password in messages
|
||||||
$error_message = $error->getMessage();
|
$error_message = $error->getMessage();
|
||||||
@@ -243,7 +260,7 @@ class Database
|
|||||||
* @param int $minLength
|
* @param int $minLength
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private static function substitute($content, array $substitutions, $minLength = 6)
|
private static function substitute(string $content, array $substitutions, int $minLength = 6): string
|
||||||
{
|
{
|
||||||
$replacements = [];
|
$replacements = [];
|
||||||
|
|
||||||
@@ -251,9 +268,7 @@ class Database
|
|||||||
$replacements += self::createShiftedSubstitutions($search, $replace, $minLength);
|
$replacements += self::createShiftedSubstitutions($search, $replace, $minLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = str_replace(array_keys($replacements), array_values($replacements), $content);
|
return str_replace(array_keys($replacements), array_values($replacements), $content);
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -273,7 +288,7 @@ class Database
|
|||||||
* @param int $minLength
|
* @param int $minLength
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private static function createShiftedSubstitutions($search, $replace, $minLength)
|
private static function createShiftedSubstitutions(string $search, string $replace, int $minLength): array
|
||||||
{
|
{
|
||||||
$substitutions = [];
|
$substitutions = [];
|
||||||
$length = strlen($search);
|
$length = strlen($search);
|
||||||
@@ -292,8 +307,9 @@ class Database
|
|||||||
*
|
*
|
||||||
* @param int $length
|
* @param int $length
|
||||||
* @return string
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private static function genUniqueToken(int $length = 16)
|
private static function genUniqueToken(int $length = 16): string
|
||||||
{
|
{
|
||||||
if (intval($length) <= 8) {
|
if (intval($length) <= 8) {
|
||||||
$length = 16;
|
$length = 16;
|
||||||
@@ -316,7 +332,7 @@ class Database
|
|||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function num_rows()
|
public static function num_rows(): int
|
||||||
{
|
{
|
||||||
return Database::query("SELECT FOUND_ROWS()")->fetchColumn();
|
return Database::query("SELECT FOUND_ROWS()")->fetchColumn();
|
||||||
}
|
}
|
||||||
@@ -326,7 +342,7 @@ class Database
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function getDbName()
|
public static function getDbName(): ?string
|
||||||
{
|
{
|
||||||
return self::$dbname;
|
return self::$dbname;
|
||||||
}
|
}
|
||||||
@@ -338,15 +354,16 @@ class Database
|
|||||||
* the 'normal' database-connection
|
* the 'normal' database-connection
|
||||||
*
|
*
|
||||||
* @param bool $needroot
|
* @param bool $needroot
|
||||||
* @param int $dbserver
|
* @param int $dbserver optional
|
||||||
* optional
|
* @param bool $need_db
|
||||||
*/
|
*/
|
||||||
public static function needRoot($needroot = false, $dbserver = 0)
|
public static function needRoot(bool $needroot = false, int $dbserver = 0, bool $need_db = true)
|
||||||
{
|
{
|
||||||
// force re-connecting to the db with corresponding user
|
// force re-connecting to the db with corresponding user
|
||||||
// and set the $dbserver (mostly to 0 = default)
|
// and set the $dbserver (mostly to 0 = default)
|
||||||
self::setServer($dbserver);
|
self::setServer($dbserver);
|
||||||
self::$needroot = $needroot;
|
self::$needroot = $needroot;
|
||||||
|
self::$need_dbname = $need_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -354,7 +371,7 @@ class Database
|
|||||||
*
|
*
|
||||||
* @param int $dbserver
|
* @param int $dbserver
|
||||||
*/
|
*/
|
||||||
private static function setServer($dbserver = 0)
|
private static function setServer(int $dbserver = 0)
|
||||||
{
|
{
|
||||||
self::$dbserver = $dbserver;
|
self::$dbserver = $dbserver;
|
||||||
self::$link = null;
|
self::$link = null;
|
||||||
@@ -385,17 +402,16 @@ class Database
|
|||||||
* function that will be called on every static call
|
* function that will be called on every static call
|
||||||
* which connects to the database if necessary
|
* which connects to the database if necessary
|
||||||
*
|
*
|
||||||
* @param bool $root
|
|
||||||
*
|
|
||||||
* @return object
|
* @return object
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private static function getDB()
|
private static function getDB()
|
||||||
{
|
{
|
||||||
if (!extension_loaded('pdo') || in_array("mysql", PDO::getAvailableDrivers()) == false) {
|
if (!extension_loaded('pdo') || !in_array("mysql", PDO::getAvailableDrivers())) {
|
||||||
self::showerror(new Exception("The php PDO extension or PDO-MySQL driver is not available"));
|
self::showerror(new Exception("The php PDO extension or PDO-MySQL driver is not available"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// do we got a connection already?
|
// do we have a connection already?
|
||||||
if (self::$link) {
|
if (self::$link) {
|
||||||
// return it
|
// return it
|
||||||
return self::$link;
|
return self::$link;
|
||||||
@@ -405,18 +421,22 @@ class Database
|
|||||||
require Froxlor::getInstallDir() . "/lib/userdata.inc.php";
|
require Froxlor::getInstallDir() . "/lib/userdata.inc.php";
|
||||||
|
|
||||||
// le format
|
// le format
|
||||||
if (self::$needroot == true && isset($sql['root_user']) && isset($sql['root_password']) && (!isset($sql_root) || !is_array($sql_root))) {
|
if (isset($sql['root_user']) && isset($sql['root_password']) && (!isset($sql_root) || !is_array($sql_root))) {
|
||||||
$sql_root = [
|
$sql_root = [
|
||||||
0 => [
|
0 => [
|
||||||
'caption' => 'Default',
|
'caption' => 'Default',
|
||||||
'host' => $sql['host'],
|
'host' => $sql['host'],
|
||||||
'socket' => (isset($sql['socket']) ? $sql['socket'] : null),
|
'socket' => ($sql['socket'] ?? null),
|
||||||
'user' => $sql['root_user'],
|
'user' => $sql['root_user'],
|
||||||
'password' => $sql['root_password']
|
'password' => $sql['root_password']
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
unset($sql['root_user']);
|
unset($sql['root_user']);
|
||||||
unset($sql['root_password']);
|
unset($sql['root_password']);
|
||||||
|
// write new layout so this won't happen again
|
||||||
|
self::generateNewUserData($sql, $sql_root);
|
||||||
|
// re-read file
|
||||||
|
require Froxlor::getInstallDir() . "/lib/userdata.inc.php";
|
||||||
}
|
}
|
||||||
|
|
||||||
// either root or unprivileged user
|
// either root or unprivileged user
|
||||||
@@ -425,8 +445,8 @@ class Database
|
|||||||
$user = $sql_root[self::$dbserver]['user'];
|
$user = $sql_root[self::$dbserver]['user'];
|
||||||
$password = $sql_root[self::$dbserver]['password'];
|
$password = $sql_root[self::$dbserver]['password'];
|
||||||
$host = $sql_root[self::$dbserver]['host'];
|
$host = $sql_root[self::$dbserver]['host'];
|
||||||
$socket = isset($sql_root[self::$dbserver]['socket']) ? $sql_root[self::$dbserver]['socket'] : null;
|
$socket = $sql_root[self::$dbserver]['socket'] ?? null;
|
||||||
$port = isset($sql_root[self::$dbserver]['port']) ? $sql_root[self::$dbserver]['port'] : '3306';
|
$port = $sql_root[self::$dbserver]['port'] ?? '3306';
|
||||||
$sslCAFile = $sql_root[self::$dbserver]['ssl']['caFile'] ?? "";
|
$sslCAFile = $sql_root[self::$dbserver]['ssl']['caFile'] ?? "";
|
||||||
$sslVerifyServerCertificate = $sql_root[self::$dbserver]['ssl']['verifyServerCertificate'] ?? false;
|
$sslVerifyServerCertificate = $sql_root[self::$dbserver]['ssl']['verifyServerCertificate'] ?? false;
|
||||||
} else {
|
} else {
|
||||||
@@ -434,8 +454,8 @@ class Database
|
|||||||
$user = $sql["user"];
|
$user = $sql["user"];
|
||||||
$password = $sql["password"];
|
$password = $sql["password"];
|
||||||
$host = $sql["host"];
|
$host = $sql["host"];
|
||||||
$socket = isset($sql['socket']) ? $sql['socket'] : null;
|
$socket = $sql['socket'] ?? null;
|
||||||
$port = isset($sql['port']) ? $sql['port'] : '3306';
|
$port = $sql['port'] ?? '3306';
|
||||||
$sslCAFile = $sql['ssl']['caFile'] ?? "";
|
$sslCAFile = $sql['ssl']['caFile'] ?? "";
|
||||||
$sslVerifyServerCertificate = $sql['ssl']['verifyServerCertificate'] ?? false;
|
$sslVerifyServerCertificate = $sql['ssl']['verifyServerCertificate'] ?? false;
|
||||||
}
|
}
|
||||||
@@ -465,10 +485,11 @@ class Database
|
|||||||
'ATTR_ERRMODE' => 'ERRMODE_EXCEPTION'
|
'ATTR_ERRMODE' => 'ERRMODE_EXCEPTION'
|
||||||
];
|
];
|
||||||
|
|
||||||
$dbconf["dsn"] = [
|
$dbconf["dsn"] = ['charset' => 'utf8'];
|
||||||
'dbname' => $sql["db"],
|
|
||||||
'charset' => 'utf8'
|
if (self::$need_dbname) {
|
||||||
];
|
$dbconf["dsn"]['dbname'] = $sql["db"];
|
||||||
|
}
|
||||||
|
|
||||||
if ($socket != null) {
|
if ($socket != null) {
|
||||||
$dbconf["dsn"]['unix_socket'] = FileDir::makeCorrectFile($socket);
|
$dbconf["dsn"]['unix_socket'] = FileDir::makeCorrectFile($socket);
|
||||||
@@ -539,14 +560,14 @@ class Database
|
|||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function getSqlUsernameLength()
|
public static function getSqlUsernameLength(): int
|
||||||
{
|
{
|
||||||
// MariaDB supports up to 80 characters but only 64 for databases and as we use the loginname also for
|
// MariaDB supports up to 80 characters but only 64 for databases and as we use the login-name also for
|
||||||
// database names, we set the limit to 64 here
|
// database names, we set the limit to 64 here
|
||||||
if (strpos(strtolower(Database::getAttribute(\PDO::ATTR_SERVER_VERSION)), "mariadb") !== false) {
|
if (strpos(strtolower(Database::getAttribute(\PDO::ATTR_SERVER_VERSION)), "mariadb") !== false) {
|
||||||
$mysql_max = 64;
|
$mysql_max = 64;
|
||||||
} else {
|
} else {
|
||||||
// MySQL user names can be up to 32 characters long (16 characters before MySQL 5.7.8).
|
// MySQL user-names can be up to 32 characters long (16 characters before MySQL 5.7.8).
|
||||||
$mysql_max = 32;
|
$mysql_max = 32;
|
||||||
if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.7.8', '<')) {
|
if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.7.8', '<')) {
|
||||||
$mysql_max = 16;
|
$mysql_max = 16;
|
||||||
@@ -556,15 +577,16 @@ class Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* let's us interact with the PDO-Object by using static
|
* Lets us interact with the PDO-Object by using static
|
||||||
* call like "Database::function()"
|
* call like "Database::function()"
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param mixed $args
|
* @param mixed $args
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function __callStatic($name, $args)
|
public static function __callStatic(string $name, $args)
|
||||||
{
|
{
|
||||||
$callback = [
|
$callback = [
|
||||||
self::getDB(),
|
self::getDB(),
|
||||||
@@ -578,4 +600,22 @@ class Database
|
|||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* write new userdata.inc.php file
|
||||||
|
*/
|
||||||
|
private static function generateNewUserData(array $sql, array $sql_root)
|
||||||
|
{
|
||||||
|
$content = PhpHelper::parseArrayToPhpFile(
|
||||||
|
['sql' => $sql, 'sql_root' => $sql_root],
|
||||||
|
'automatically generated userdata.inc.php for froxlor'
|
||||||
|
);
|
||||||
|
chmod(Froxlor::getInstallDir() . "/lib/userdata.inc.php", 0700);
|
||||||
|
file_put_contents(Froxlor::getInstallDir() . "/lib/userdata.inc.php", $content);
|
||||||
|
chmod(Froxlor::getInstallDir() . "/lib/userdata.inc.php", 0400);
|
||||||
|
clearstatcache();
|
||||||
|
if (function_exists('opcache_invalidate')) {
|
||||||
|
@opcache_invalidate(Froxlor::getInstallDir() . "/lib/userdata.inc.php", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,15 @@ class DbManager
|
|||||||
$this->manager = new DbManagerMySQL($this->log);
|
$this->manager = new DbManagerMySQL($this->log);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function correctMysqlUsers($mysql_access_host_array)
|
/**
|
||||||
|
* function called when the mysql-access-host setting changes
|
||||||
|
*
|
||||||
|
* @param array $mysql_access_host_array
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function correctMysqlUsers(array $mysql_access_host_array)
|
||||||
{
|
{
|
||||||
// get all databases for all dbservers
|
// get all databases for all dbservers
|
||||||
$databases = [];
|
$databases = [];
|
||||||
@@ -96,12 +104,12 @@ class DbManager
|
|||||||
$dbservers_stmt = Database::query("SELECT DISTINCT `dbserver` FROM `" . TABLE_PANEL_DATABASES . "`");
|
$dbservers_stmt = Database::query("SELECT DISTINCT `dbserver` FROM `" . TABLE_PANEL_DATABASES . "`");
|
||||||
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
// require privileged access for target db-server
|
// require privileged access for target db-server
|
||||||
Database::needRoot(true, $dbserver['dbserver']);
|
Database::needRoot(true, $dbserver['dbserver'], false);
|
||||||
|
|
||||||
$dbm = new DbManager(FroxlorLogger::getInstanceOf());
|
$dbm = new DbManager(FroxlorLogger::getInstanceOf());
|
||||||
$users = $dbm->getManager()->getAllSqlUsers(false);
|
$users = $dbm->getManager()->getAllSqlUsers(false);
|
||||||
|
|
||||||
foreach ($databases[$dbserver] as $username) {
|
foreach ($databases[$dbserver['dbserver']] as $username) {
|
||||||
if (isset($users[$username]) && is_array($users[$username]) && isset($users[$username]['hosts']) && is_array($users[$username]['hosts'])) {
|
if (isset($users[$username]) && is_array($users[$username]) && isset($users[$username]['hosts']) && is_array($users[$username]['hosts'])) {
|
||||||
|
|
||||||
$password = [
|
$password = [
|
||||||
@@ -136,15 +144,16 @@ class DbManager
|
|||||||
* DB-name and user-name are being generated and
|
* DB-name and user-name are being generated and
|
||||||
* the password for the user will be set
|
* the password for the user will be set
|
||||||
*
|
*
|
||||||
* @param string $loginname
|
* @param ?string $loginname
|
||||||
* @param string $password
|
* @param ?string $password
|
||||||
|
* @param int $dbserver
|
||||||
* @param int $last_accnumber
|
* @param int $last_accnumber
|
||||||
*
|
*
|
||||||
* @return string|bool $username if successful or false of username is equal to the password
|
* @return string|bool $username if successful or false of username is equal to the password
|
||||||
*/
|
*/
|
||||||
public function createDatabase($loginname = null, $password = null, int $dbserver = 0, $last_accnumber = 0)
|
public function createDatabase(string $loginname = null, string $password = null, int $dbserver = 0, int $last_accnumber = 0)
|
||||||
{
|
{
|
||||||
Database::needRoot(true, $dbserver);
|
Database::needRoot(true, $dbserver, false);
|
||||||
|
|
||||||
// check whether we shall create a random username
|
// check whether we shall create a random username
|
||||||
if (strtoupper(Settings::Get('customer.mysqlprefix')) == 'RANDOM') {
|
if (strtoupper(Settings::Get('customer.mysqlprefix')) == 'RANDOM') {
|
||||||
@@ -169,18 +178,17 @@ class DbManager
|
|||||||
|
|
||||||
// now create the database itself
|
// now create the database itself
|
||||||
$this->getManager()->createDatabase($username);
|
$this->getManager()->createDatabase($username);
|
||||||
$this->log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "created database '" . $username . "'");
|
|
||||||
|
|
||||||
// and give permission to the user on every access-host we have
|
// and 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) {
|
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
|
||||||
$this->getManager()->grantPrivilegesTo($username, $password, $mysql_access_host);
|
$this->getManager()->grantPrivilegesTo($username, $password, $mysql_access_host);
|
||||||
$this->log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "grant all privileges for '" . $username . "'@'" . $mysql_access_host . "'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getManager()->flushPrivileges();
|
$this->getManager()->flushPrivileges();
|
||||||
|
|
||||||
Database::needRoot(false);
|
Database::needRoot(false);
|
||||||
|
|
||||||
|
$this->log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "created database '" . $username . "'");
|
||||||
|
|
||||||
return $username;
|
return $username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,21 +85,22 @@ class IntegrityCheck
|
|||||||
/**
|
/**
|
||||||
* check whether the froxlor database and its tables are in utf-8 character-set
|
* check whether the froxlor database and its tables are in utf-8 character-set
|
||||||
*
|
*
|
||||||
* @param bool $fix
|
* @param bool $fix fix db charset/collation if not utf8
|
||||||
* fix db charset/collation if not utf8
|
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function databaseCharset($fix = false)
|
public function databaseCharset(bool $fix = false): bool
|
||||||
{
|
{
|
||||||
// get characterset
|
// get character-set
|
||||||
$cs_stmt = Database::prepare('SELECT default_character_set_name FROM information_schema.SCHEMATA WHERE schema_name = :dbname');
|
$cs_stmt = Database::prepare('SELECT default_character_set_name FROM information_schema.SCHEMATA WHERE schema_name = :dbname');
|
||||||
$resp = Database::pexecute_first($cs_stmt, [
|
$resp = Database::pexecute_first($cs_stmt, [
|
||||||
'dbname' => Database::getDbName()
|
'dbname' => Database::getDbName()
|
||||||
]);
|
]);
|
||||||
$charset = isset($resp['default_character_set_name']) ? $resp['default_character_set_name'] : null;
|
$charset = $resp['default_character_set_name'] ?? null;
|
||||||
if (!empty($charset) && substr(strtolower($charset), 0, 4) != 'utf8') {
|
if (!empty($charset) && substr(strtolower($charset), 0, 4) != 'utf8') {
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "database charset seems to be different from UTF-8, integrity-check can fix that");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE,
|
||||||
|
"database charset seems to be different from UTF-8, integrity-check can fix that");
|
||||||
if ($fix) {
|
if ($fix) {
|
||||||
// fix database
|
// fix database
|
||||||
Database::query('ALTER DATABASE `' . Database::getDbName() . '` CHARACTER SET utf8 COLLATE utf8_general_ci');
|
Database::query('ALTER DATABASE `' . Database::getDbName() . '` CHARACTER SET utf8 COLLATE utf8_general_ci');
|
||||||
@@ -109,7 +110,8 @@ class IntegrityCheck
|
|||||||
$table = $row[0];
|
$table = $row[0];
|
||||||
Database::query('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;');
|
Database::query('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;');
|
||||||
}
|
}
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "database charset was different from UTF-8, integrity-check fixed that");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING,
|
||||||
|
"database charset was different from UTF-8, integrity-check fixed that");
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -124,10 +126,12 @@ class IntegrityCheck
|
|||||||
/**
|
/**
|
||||||
* Check the integrity of the domain to ip/port - association
|
* Check the integrity of the domain to ip/port - association
|
||||||
*
|
*
|
||||||
* @param bool $fix
|
* @param bool $fix fix everything found directly
|
||||||
* Fix everything found directly
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function domainIpTable($fix = false)
|
public function domainIpTable(bool $fix = false): bool
|
||||||
{
|
{
|
||||||
$ips = [];
|
$ips = [];
|
||||||
$domains = [];
|
$domains = [];
|
||||||
@@ -184,9 +188,11 @@ class IntegrityCheck
|
|||||||
'domainid' => $row['id_domain'],
|
'domainid' => $row['id_domain'],
|
||||||
'ipandportid' => $row['id_ipandports']
|
'ipandportid' => $row['id_ipandports']
|
||||||
]);
|
]);
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "found an ip/port-id in domain <> ip table which does not exist, integrity check fixed this");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING,
|
||||||
|
"found an ip/port-id in domain <> ip table which does not exist, integrity check fixed this");
|
||||||
} else {
|
} else {
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "found an ip/port-id in domain <> ip table which does not exist, integrity check can fix this");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE,
|
||||||
|
"found an ip/port-id in domain <> ip table which does not exist, integrity check can fix this");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,9 +202,11 @@ class IntegrityCheck
|
|||||||
'domainid' => $row['id_domain'],
|
'domainid' => $row['id_domain'],
|
||||||
'ipandportid' => $row['id_ipandports']
|
'ipandportid' => $row['id_ipandports']
|
||||||
]);
|
]);
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "found a domain-id in domain <> ip table which does not exist, integrity check fixed this");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING,
|
||||||
|
"found a domain-id in domain <> ip table which does not exist, integrity check fixed this");
|
||||||
} else {
|
} else {
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "found a domain-id in domain <> ip table which does not exist, integrity check can fix this");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE,
|
||||||
|
"found a domain-id in domain <> ip table which does not exist, integrity check can fix this");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,9 +224,11 @@ class IntegrityCheck
|
|||||||
'ipandportid' => $defaultip
|
'ipandportid' => $defaultip
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "found a domain-id with no entry in domain <> ip table, integrity check fixed this");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING,
|
||||||
|
"found a domain-id with no entry in domain <> ip table, integrity check fixed this");
|
||||||
} else {
|
} else {
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "found a domain-id with no entry in domain <> ip table, integrity check can fix this");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE,
|
||||||
|
"found a domain-id with no entry in domain <> ip table, integrity check can fix this");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,18 +236,19 @@ class IntegrityCheck
|
|||||||
|
|
||||||
if ($fix) {
|
if ($fix) {
|
||||||
return $this->domainIpTable();
|
return $this->domainIpTable();
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if all subdomains have ssl-redirect = 0 if domain has no ssl-port
|
* Check if all subdomains have ssl-redirect = 0 if domain has no ssl-port
|
||||||
*
|
*
|
||||||
* @param bool $fix
|
* @param bool $fix fix everything found directly
|
||||||
* Fix everything found directly
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function subdomainSslRedirect($fix = false)
|
public function subdomainSslRedirect(bool $fix = false): bool
|
||||||
{
|
{
|
||||||
$ips = [];
|
$ips = [];
|
||||||
$parentdomains = [];
|
$parentdomains = [];
|
||||||
@@ -300,28 +311,31 @@ class IntegrityCheck
|
|||||||
Database::pexecute($upd_stmt, [
|
Database::pexecute($upd_stmt, [
|
||||||
'domainid' => $id
|
'domainid' => $id
|
||||||
]);
|
]);
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "found a subdomain with ssl_redirect=1 but parent-domain has ssl=0, integrity check fixed this");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING,
|
||||||
|
"found a subdomain with ssl_redirect=1 but parent-domain has ssl=0, integrity check fixed this");
|
||||||
} else {
|
} else {
|
||||||
// It's just the check, let the function fail
|
// It's just the check, let the function fail
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "found a subdomain with ssl_redirect=1 but parent-domain has ssl=0, integrity check can fix this");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE,
|
||||||
|
"found a subdomain with ssl_redirect=1 but parent-domain has ssl=0, integrity check can fix this");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($fix) {
|
if ($fix) {
|
||||||
return $this->subdomainSslRedirect();
|
return $this->subdomainSslRedirect();
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if all subdomain have letsencrypt = 0 if domain has no ssl-port
|
* Check if all subdomain have letsencrypt = 0 if domain has no ssl-port
|
||||||
*
|
*
|
||||||
* @param bool $fix
|
* @param bool $fix fix everything found directly
|
||||||
* Fix everything found directly
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function subdomainLetsencrypt($fix = false)
|
public function subdomainLetsencrypt(bool $fix = false): bool
|
||||||
{
|
{
|
||||||
$ips = [];
|
$ips = [];
|
||||||
$parentdomains = [];
|
$parentdomains = [];
|
||||||
@@ -384,31 +398,32 @@ class IntegrityCheck
|
|||||||
Database::pexecute($upd_stmt, [
|
Database::pexecute($upd_stmt, [
|
||||||
'domainid' => $id
|
'domainid' => $id
|
||||||
]);
|
]);
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "found a subdomain with letsencrypt=1 but parent-domain has ssl=0, integrity check fixed this");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING,
|
||||||
|
"found a subdomain with letsencrypt=1 but parent-domain has ssl=0, integrity check fixed this");
|
||||||
} else {
|
} else {
|
||||||
// It's just the check, let the function fail
|
// It's just the check, let the function fail
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "found a subdomain with letsencrypt=1 but parent-domain has ssl=0, integrity check can fix this");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE,
|
||||||
|
"found a subdomain with letsencrypt=1 but parent-domain has ssl=0, integrity check can fix this");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($fix) {
|
if ($fix) {
|
||||||
return $this->subdomainLetsencrypt();
|
return $this->subdomainLetsencrypt();
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check whether the webserveruser is in
|
* check whether the webserveruser is in
|
||||||
* the customers groups when fcgid / php-fpm is used
|
* the customers groups when fcgid / php-fpm is used
|
||||||
*
|
*
|
||||||
* @param bool $fix
|
* @param bool $fix fix member/groups
|
||||||
* fix member/groups
|
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function webserverGroupMemberForFcgidPhpFpm($fix = false)
|
public function webserverGroupMemberForFcgidPhpFpm(bool $fix = false): bool
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.mod_fcgid') == 0 && Settings::Get('phpfpm.enabled') == 0) {
|
if (Settings::Get('system.mod_fcgid') == 0 && Settings::Get('phpfpm.enabled') == 0) {
|
||||||
return true;
|
return true;
|
||||||
@@ -423,7 +438,8 @@ class IntegrityCheck
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if ($cwg_stmt->rowCount() > 0) {
|
if ($cwg_stmt->rowCount() > 0) {
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Customers are missing the webserver-user as group-member, integrity-check can fix that");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE,
|
||||||
|
"Customers are missing the webserver-user as group-member, integrity-check can fix that");
|
||||||
if ($fix) {
|
if ($fix) {
|
||||||
// prepare update statement
|
// prepare update statement
|
||||||
$upd_stmt = Database::prepare("
|
$upd_stmt = Database::prepare("
|
||||||
@@ -438,7 +454,8 @@ class IntegrityCheck
|
|||||||
$upd_data['id'] = $cwg_row['id'];
|
$upd_data['id'] = $cwg_row['id'];
|
||||||
Database::pexecute($upd_stmt, $upd_data);
|
Database::pexecute($upd_stmt, $upd_data);
|
||||||
}
|
}
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Customers were missing the webserver-user as group-member, integrity-check fixed that");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE,
|
||||||
|
"Customers were missing the webserver-user as group-member, integrity-check fixed that");
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -455,12 +472,12 @@ class IntegrityCheck
|
|||||||
* the customers groups when fcgid / php-fpm and
|
* the customers groups when fcgid / php-fpm and
|
||||||
* fcgid/fpm in froxlor vhost is used
|
* fcgid/fpm in froxlor vhost is used
|
||||||
*
|
*
|
||||||
* @param bool $fix
|
* @param bool $fix fix member/groups
|
||||||
* fix member/groups
|
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function froxlorLocalGroupMemberForFcgidPhpFpm($fix = false)
|
public function froxlorLocalGroupMemberForFcgidPhpFpm(bool $fix = false): bool
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.mod_fcgid') == 0 && Settings::Get('phpfpm.enabled') == 0) {
|
if (Settings::Get('system.mod_fcgid') == 0 && Settings::Get('phpfpm.enabled') == 0) {
|
||||||
return true;
|
return true;
|
||||||
@@ -491,7 +508,8 @@ class IntegrityCheck
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if ($cwg_stmt->rowCount() > 0) {
|
if ($cwg_stmt->rowCount() > 0) {
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Customers are missing the local froxlor-user as group-member, integrity-check can fix that");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE,
|
||||||
|
"Customers are missing the local froxlor-user as group-member, integrity-check can fix that");
|
||||||
if ($fix) {
|
if ($fix) {
|
||||||
// prepare update statement
|
// prepare update statement
|
||||||
$upd_stmt = Database::prepare("
|
$upd_stmt = Database::prepare("
|
||||||
@@ -506,7 +524,8 @@ class IntegrityCheck
|
|||||||
$upd_data['id'] = $cwg_row['id'];
|
$upd_data['id'] = $cwg_row['id'];
|
||||||
Database::pexecute($upd_stmt, $upd_data);
|
Database::pexecute($upd_stmt, $upd_data);
|
||||||
}
|
}
|
||||||
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Customers were missing the local froxlor-user as group-member, integrity-check fixed that");
|
$this->log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE,
|
||||||
|
"Customers were missing the local froxlor-user as group-member, integrity-check fixed that");
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class DbManagerMySQL
|
|||||||
/**
|
/**
|
||||||
* main constructor
|
* main constructor
|
||||||
*
|
*
|
||||||
* @param FroxlorLogger $log
|
* @param FroxlorLogger|null $log
|
||||||
*/
|
*/
|
||||||
public function __construct(&$log = null)
|
public function __construct(&$log = null)
|
||||||
{
|
{
|
||||||
@@ -58,9 +58,9 @@ class DbManagerMySQL
|
|||||||
/**
|
/**
|
||||||
* creates a database
|
* creates a database
|
||||||
*
|
*
|
||||||
* @param string $dbname
|
* @param string|null $dbname
|
||||||
*/
|
*/
|
||||||
public function createDatabase($dbname = null)
|
public function createDatabase(string $dbname = null)
|
||||||
{
|
{
|
||||||
Database::query("CREATE DATABASE `" . $dbname . "`");
|
Database::query("CREATE DATABASE `" . $dbname . "`");
|
||||||
}
|
}
|
||||||
@@ -71,13 +71,14 @@ class DbManagerMySQL
|
|||||||
*
|
*
|
||||||
* @param string $username
|
* @param string $username
|
||||||
* @param string|array $password
|
* @param string|array $password
|
||||||
* @param string $access_host
|
* @param ?string $access_host
|
||||||
* @param bool $p_encrypted
|
* @param bool $p_encrypted
|
||||||
* optional, whether the password is encrypted or not, default false
|
* optional, whether the password is encrypted or not, default false
|
||||||
* @param bool $update
|
* @param bool $update
|
||||||
* optional, whether to update the password only (not create user)
|
* optional, whether to update the password only (not create user)
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function grantPrivilegesTo($username = null, $password = null, $access_host = null, $p_encrypted = false, $update = false)
|
public function grantPrivilegesTo(string $username, $password, string $access_host = null, bool $p_encrypted = false, bool $update = false)
|
||||||
{
|
{
|
||||||
$pwd_plugin = 'mysql_native_password';
|
$pwd_plugin = 'mysql_native_password';
|
||||||
if (is_array($password) && count($password) == 2) {
|
if (is_array($password) && count($password) == 2) {
|
||||||
@@ -141,8 +142,9 @@ class DbManagerMySQL
|
|||||||
* takes away any privileges from a user to that db
|
* takes away any privileges from a user to that db
|
||||||
*
|
*
|
||||||
* @param string $dbname
|
* @param string $dbname
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function deleteDatabase($dbname = null)
|
public function deleteDatabase(string $dbname)
|
||||||
{
|
{
|
||||||
if (version_compare(Database::getAttribute(PDO::ATTR_SERVER_VERSION), '5.0.2', '<')) {
|
if (version_compare(Database::getAttribute(PDO::ATTR_SERVER_VERSION), '5.0.2', '<')) {
|
||||||
// failsafe if user has been deleted manually (requires MySQL 4.1.2+)
|
// failsafe if user has been deleted manually (requires MySQL 4.1.2+)
|
||||||
@@ -178,8 +180,9 @@ class DbManagerMySQL
|
|||||||
*
|
*
|
||||||
* @param string $username
|
* @param string $username
|
||||||
* @param string $host
|
* @param string $host
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function deleteUser($username = null, $host = null)
|
public function deleteUser(string $username, string $host)
|
||||||
{
|
{
|
||||||
if (Database::getAttribute(PDO::ATTR_SERVER_VERSION) < '5.0.2') {
|
if (Database::getAttribute(PDO::ATTR_SERVER_VERSION) < '5.0.2') {
|
||||||
// Revoke privileges (only required for MySQL 4.1.2 - 5.0.1)
|
// Revoke privileges (only required for MySQL 4.1.2 - 5.0.1)
|
||||||
@@ -203,9 +206,9 @@ class DbManagerMySQL
|
|||||||
*
|
*
|
||||||
* @param string $username
|
* @param string $username
|
||||||
* @param string $host
|
* @param string $host
|
||||||
* (unused in mysql)
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function disableUser($username = null, $host = null)
|
public function disableUser(string $username, string $host)
|
||||||
{
|
{
|
||||||
$stmt = Database::prepare('REVOKE ALL PRIVILEGES, GRANT OPTION FROM `' . $username . '`@`' . $host . '`');
|
$stmt = Database::prepare('REVOKE ALL PRIVILEGES, GRANT OPTION FROM `' . $username . '`@`' . $host . '`');
|
||||||
Database::pexecute($stmt, [], false);
|
Database::pexecute($stmt, [], false);
|
||||||
@@ -216,8 +219,9 @@ class DbManagerMySQL
|
|||||||
*
|
*
|
||||||
* @param string $username
|
* @param string $username
|
||||||
* @param string $host
|
* @param string $host
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function enableUser($username = null, $host = null)
|
public function enableUser(string $username, string $host)
|
||||||
{
|
{
|
||||||
// check whether user exists to avoid errors
|
// check whether user exists to avoid errors
|
||||||
$exist_check_stmt = Database::prepare("SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '" . $username . "' AND host = '" . $host . "')");
|
$exist_check_stmt = Database::prepare("SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '" . $username . "' AND host = '" . $host . "')");
|
||||||
@@ -239,14 +243,14 @@ class DbManagerMySQL
|
|||||||
/**
|
/**
|
||||||
* return an array of all usernames used in that DBMS
|
* return an array of all usernames used in that DBMS
|
||||||
*
|
*
|
||||||
* @param bool $user_only
|
* @param bool $user_only if false, will be selected from mysql.user and slightly different array will be generated
|
||||||
* if false, * will be selected from mysql.user and slightly different array will be generated
|
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function getAllSqlUsers($user_only = true)
|
public function getAllSqlUsers(bool $user_only = true): array
|
||||||
{
|
{
|
||||||
if ($user_only == false) {
|
if (!$user_only) {
|
||||||
$result_stmt = Database::prepare('SELECT * FROM mysql.user');
|
$result_stmt = Database::prepare('SELECT * FROM mysql.user');
|
||||||
} else {
|
} else {
|
||||||
$result_stmt = Database::prepare('SELECT `User` FROM mysql.user');
|
$result_stmt = Database::prepare('SELECT `User` FROM mysql.user');
|
||||||
|
|||||||
@@ -33,7 +33,15 @@ use PDO;
|
|||||||
|
|
||||||
class Dns
|
class Dns
|
||||||
{
|
{
|
||||||
public static function getAllowedDomainEntry($domain_id, $area = 'customer', $userinfo = [])
|
/**
|
||||||
|
* @param int $domain_id
|
||||||
|
* @param string $area
|
||||||
|
* @param array $userinfo
|
||||||
|
*
|
||||||
|
* @return string|void
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function getAllowedDomainEntry(int $domain_id, string $area = 'customer', array $userinfo = [])
|
||||||
{
|
{
|
||||||
$dom_data = [
|
$dom_data = [
|
||||||
'did' => $domain_id
|
'did' => $domain_id
|
||||||
@@ -67,7 +75,15 @@ class Dns
|
|||||||
Response::standardError('dns_notfoundorallowed');
|
Response::standardError('dns_notfoundorallowed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function createDomainZone($domain_id, $froxlorhostname = false, $isMainButSubTo = false)
|
/**
|
||||||
|
* @param int|array $domain_id id of domain or in case of froxlorhostname, a domain-array with the needed data
|
||||||
|
* @param bool $froxlorhostname
|
||||||
|
* @param bool $isMainButSubTo
|
||||||
|
*
|
||||||
|
* @return DnsZone|void
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function createDomainZone($domain_id, bool $froxlorhostname = false, bool $isMainButSubTo = false)
|
||||||
{
|
{
|
||||||
if (!$froxlorhostname) {
|
if (!$froxlorhostname) {
|
||||||
// get domain-name
|
// get domain-name
|
||||||
@@ -136,7 +152,7 @@ class Dns
|
|||||||
if (!$froxlorhostname) {
|
if (!$froxlorhostname) {
|
||||||
// additional required records for subdomains
|
// additional required records for subdomains
|
||||||
$subdomains_stmt = Database::prepare("
|
$subdomains_stmt = Database::prepare("
|
||||||
SELECT `domain`, `iswildcarddomain`, `wwwserveralias` FROM `" . TABLE_PANEL_DOMAINS . "`
|
SELECT `domain`, `iswildcarddomain`, `wwwserveralias`, `isemaildomain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE `parentdomainid` = :domainid
|
WHERE `parentdomainid` = :domainid
|
||||||
");
|
");
|
||||||
Database::pexecute($subdomains_stmt, [
|
Database::pexecute($subdomains_stmt, [
|
||||||
@@ -144,18 +160,31 @@ class Dns
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
while ($subdomain = $subdomains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($subdomain = $subdomains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$sub_record = str_replace('.' . $domain['domain'], '', $subdomain['domain']);
|
||||||
// Listing domains is enough as there currently is no support for choosing
|
// Listing domains is enough as there currently is no support for choosing
|
||||||
// different ips for a subdomain => use same IPs as toplevel
|
// different ips for a subdomain => use same IPs as toplevel
|
||||||
self::addRequiredEntry(str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'A', $required_entries);
|
self::addRequiredEntry($sub_record, 'A',$required_entries);
|
||||||
self::addRequiredEntry(str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'AAAA', $required_entries);
|
self::addRequiredEntry($sub_record, 'AAAA', $required_entries);
|
||||||
|
|
||||||
// Check whether to add a www.-prefix
|
// Check whether to add a www.-prefix
|
||||||
if ($subdomain['iswildcarddomain'] == '1') {
|
if ($subdomain['iswildcarddomain'] == '1') {
|
||||||
self::addRequiredEntry('*.' . str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'A', $required_entries);
|
self::addRequiredEntry('*.' . $sub_record, 'A', $required_entries);
|
||||||
self::addRequiredEntry('*.' . str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'AAAA', $required_entries);
|
self::addRequiredEntry('*.' . $sub_record, 'AAAA', $required_entries);
|
||||||
} elseif ($subdomain['wwwserveralias'] == '1') {
|
} elseif ($subdomain['wwwserveralias'] == '1') {
|
||||||
self::addRequiredEntry('www.' . str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'A', $required_entries);
|
self::addRequiredEntry('www.' . $sub_record, 'A', $required_entries);
|
||||||
self::addRequiredEntry('www.' . str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'AAAA', $required_entries);
|
self::addRequiredEntry('www.' . $sub_record, 'AAAA', $required_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for email ability
|
||||||
|
if ($subdomain['isemaildomain'] == '1') {
|
||||||
|
if (Settings::Get('spf.use_spf') == '1') {
|
||||||
|
// check for SPF content later
|
||||||
|
self::addRequiredEntry('@SPF@.' . $sub_record, 'TXT', $required_entries);
|
||||||
|
}
|
||||||
|
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||||
|
// check for DKIM content later
|
||||||
|
self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey.' . $sub_record, 'TXT', $required_entries);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,14 +229,17 @@ class Dns
|
|||||||
|
|
||||||
// now generate all records and unset the required entries we have
|
// now generate all records and unset the required entries we have
|
||||||
foreach ($dom_entries as $entry) {
|
foreach ($dom_entries as $entry) {
|
||||||
if (array_key_exists($entry['type'], $required_entries) && array_key_exists(md5($entry['record']), $required_entries[$entry['type']])) {
|
if (array_key_exists($entry['type'], $required_entries) && array_key_exists(md5($entry['record']),
|
||||||
|
$required_entries[$entry['type']])) {
|
||||||
unset($required_entries[$entry['type']][md5($entry['record'])]);
|
unset($required_entries[$entry['type']][md5($entry['record'])]);
|
||||||
}
|
}
|
||||||
if (Settings::Get('system.dns_createcaaentry') == '1' && $entry['type'] == 'CAA' && strtolower(substr($entry['content'], 0, 7)) == '"v=caa1') {
|
if (Settings::Get('system.dns_createcaaentry') == '1' && $entry['type'] == 'CAA' && strtolower(substr($entry['content'],
|
||||||
|
0, 7)) == '"v=caa1') {
|
||||||
// unset special CAA required-entry
|
// unset special CAA required-entry
|
||||||
unset($required_entries[$entry['type']][md5("@CAA@")]);
|
unset($required_entries[$entry['type']][md5("@CAA@")]);
|
||||||
}
|
}
|
||||||
if (Settings::Get('spf.use_spf') == '1' && $entry['type'] == 'TXT' && $entry['record'] == '@' && (strtolower(substr($entry['content'], 0, 7)) == '"v=spf1' || strtolower(substr($entry['content'], 0, 6)) == 'v=spf1')) {
|
if (Settings::Get('spf.use_spf') == '1' && $entry['type'] == 'TXT' && $entry['record'] == '@' && (strtolower(substr($entry['content'],
|
||||||
|
0, 7)) == '"v=spf1' || strtolower(substr($entry['content'], 0, 6)) == 'v=spf1')) {
|
||||||
// unset special spf required-entry
|
// unset special spf required-entry
|
||||||
unset($required_entries[$entry['type']][md5("@SPF@")]);
|
unset($required_entries[$entry['type']][md5("@SPF@")]);
|
||||||
}
|
}
|
||||||
@@ -223,7 +255,8 @@ class Dns
|
|||||||
'*'
|
'*'
|
||||||
] as $crecord
|
] as $crecord
|
||||||
) {
|
) {
|
||||||
if ($entry['type'] == 'CNAME' && $entry['record'] == '@' && (array_key_exists(md5($crecord), $required_entries['A']) || array_key_exists(md5($crecord), $required_entries['AAAA']))) {
|
if ($entry['type'] == 'CNAME' && $entry['record'] == '@' && (array_key_exists(md5($crecord),
|
||||||
|
$required_entries['A']) || array_key_exists(md5($crecord), $required_entries['AAAA']))) {
|
||||||
unset($required_entries['A'][md5($crecord)]);
|
unset($required_entries['A'][md5($crecord)]);
|
||||||
unset($required_entries['AAAA'][md5($crecord)]);
|
unset($required_entries['AAAA'][md5($crecord)]);
|
||||||
}
|
}
|
||||||
@@ -238,13 +271,15 @@ class Dns
|
|||||||
'smtp'
|
'smtp'
|
||||||
] as $crecord
|
] as $crecord
|
||||||
) {
|
) {
|
||||||
if ($entry['type'] == 'CNAME' && $entry['record'] == $crecord && (array_key_exists(md5($crecord), $required_entries['A']) || array_key_exists(md5($crecord), $required_entries['AAAA']))) {
|
if ($entry['type'] == 'CNAME' && $entry['record'] == $crecord && (array_key_exists(md5($crecord),
|
||||||
|
$required_entries['A']) || array_key_exists(md5($crecord),
|
||||||
|
$required_entries['AAAA']))) {
|
||||||
unset($required_entries['A'][md5($crecord)]);
|
unset($required_entries['A'][md5($crecord)]);
|
||||||
unset($required_entries['AAAA'][md5($crecord)]);
|
unset($required_entries['AAAA'][md5($crecord)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$zonerecords[] = new DnsEntry($entry['record'], $entry['type'], $entry['content'], $entry['prio'], $entry['ttl']);
|
$zonerecords[] = new DnsEntry($entry['record'], $entry['type'], $entry['content'], $entry['prio'] ?? 0, $entry['ttl']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add missing required entries
|
// add missing required entries
|
||||||
@@ -275,7 +310,8 @@ class Dns
|
|||||||
foreach ($records as $record) {
|
foreach ($records as $record) {
|
||||||
if ($type == 'A' && filter_var($ip['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
|
if ($type == 'A' && filter_var($ip['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
|
||||||
$zonerecords[] = new DnsEntry($record, 'A', $ip['ip']);
|
$zonerecords[] = new DnsEntry($record, 'A', $ip['ip']);
|
||||||
} elseif ($type == 'AAAA' && filter_var($ip['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
|
} elseif ($type == 'AAAA' && filter_var($ip['ip'], FILTER_VALIDATE_IP,
|
||||||
|
FILTER_FLAG_IPV6) !== false) {
|
||||||
$zonerecords[] = new DnsEntry($record, 'AAAA', $ip['ip']);
|
$zonerecords[] = new DnsEntry($record, 'AAAA', $ip['ip']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,15 +384,34 @@ class Dns
|
|||||||
if ($type == 'TXT') {
|
if ($type == 'TXT') {
|
||||||
foreach ($records as $record) {
|
foreach ($records as $record) {
|
||||||
if ($record == '@SPF@') {
|
if ($record == '@SPF@') {
|
||||||
|
// spf for main-domain
|
||||||
$txt_content = Settings::Get('spf.spf_entry');
|
$txt_content = Settings::Get('spf.spf_entry');
|
||||||
$zonerecords[] = new DnsEntry('@', 'TXT', self::encloseTXTContent($txt_content));
|
$zonerecords[] = new DnsEntry('@', 'TXT', self::encloseTXTContent($txt_content));
|
||||||
} elseif ($record == 'dkim' . $domain['dkim_id'] . '._domainkey' && !empty($dkim_entries)) {
|
} elseif (strlen($record) > 6 && substr($record, 0, 6) == '@SPF@.') {
|
||||||
|
// spf for subdomain
|
||||||
|
$txt_content = Settings::Get('spf.spf_entry');
|
||||||
|
$sub_record = substr($record, 6);
|
||||||
|
$zonerecords[] = new DnsEntry($sub_record, 'TXT', self::encloseTXTContent($txt_content));
|
||||||
|
} elseif (!empty($dkim_entries)) {
|
||||||
|
// DKIM entries
|
||||||
|
$dkim_record = 'dkim' . $domain['dkim_id'] . '._domainkey';
|
||||||
|
if ($record == $dkim_record) {
|
||||||
|
// dkim for main-domain
|
||||||
// check for multiline entry
|
// check for multiline entry
|
||||||
$multiline = false;
|
$multiline = false;
|
||||||
if (substr($dkim_entries[0], 0, 1) == '(') {
|
if (substr($dkim_entries[0], 0, 1) == '(') {
|
||||||
$multiline = true;
|
$multiline = true;
|
||||||
}
|
}
|
||||||
$zonerecords[] = new DnsEntry($record, 'TXT', self::encloseTXTContent($dkim_entries[0], $multiline));
|
$zonerecords[] = new DnsEntry($record, 'TXT', self::encloseTXTContent($dkim_entries[0], $multiline));
|
||||||
|
} elseif (strlen($record) > strlen($dkim_record) && substr($record, 0, strlen($dkim_record)+1) == $dkim_record . '.') {
|
||||||
|
// dkim for subdomain-domain
|
||||||
|
// check for multiline entry
|
||||||
|
$multiline = false;
|
||||||
|
if (substr($dkim_entries[0], 0, 1) == '(') {
|
||||||
|
$multiline = true;
|
||||||
|
}
|
||||||
|
$zonerecords[] = new DnsEntry($record, 'TXT', self::encloseTXTContent($dkim_entries[0], $multiline));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -416,7 +471,8 @@ class Dns
|
|||||||
|
|
||||||
if (!$isMainButSubTo) {
|
if (!$isMainButSubTo) {
|
||||||
$date = date('Ymd');
|
$date = date('Ymd');
|
||||||
$domain['bindserial'] = (preg_match('/^' . $date . '/', $domain['bindserial']) ? $domain['bindserial'] + 1 : $date . '00');
|
$domain['bindserial'] = (preg_match('/^' . $date . '/',
|
||||||
|
$domain['bindserial']) ? $domain['bindserial'] + 1 : $date . '00');
|
||||||
if (!$froxlorhostname) {
|
if (!$froxlorhostname) {
|
||||||
$upd_stmt = Database::prepare("
|
$upd_stmt = Database::prepare("
|
||||||
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
|
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
|
||||||
@@ -443,12 +499,19 @@ class Dns
|
|||||||
array_unshift($zonerecords, $soa_record);
|
array_unshift($zonerecords, $soa_record);
|
||||||
}
|
}
|
||||||
|
|
||||||
$zone = new DnsZone((int)Settings::Get('system.defaultttl'), $domain['domain'], $domain['bindserial'], $zonerecords);
|
$zone = new DnsZone((int)Settings::Get('system.defaultttl'), $domain['domain'], $domain['bindserial'],
|
||||||
|
$zonerecords);
|
||||||
|
|
||||||
return $zone;
|
return $zone;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function addRequiredEntry($record = '@', $type = 'A', &$required = [])
|
/**
|
||||||
|
* @param string $record
|
||||||
|
* @param string $type
|
||||||
|
* @param array $required
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function addRequiredEntry(string $record = '@', string $type = 'A', array &$required = [])
|
||||||
{
|
{
|
||||||
if (!isset($required[$type])) {
|
if (!isset($required[$type])) {
|
||||||
$required[$type] = [];
|
$required[$type] = [];
|
||||||
@@ -456,7 +519,11 @@ class Dns
|
|||||||
$required[$type][md5($record)] = $record;
|
$required[$type][md5($record)] = $record;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function generateDkimEntries($domain)
|
/**
|
||||||
|
* @param array $domain
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function generateDkimEntries(array $domain): array
|
||||||
{
|
{
|
||||||
$zone_dkim = [];
|
$zone_dkim = [];
|
||||||
|
|
||||||
@@ -486,7 +553,8 @@ class Dns
|
|||||||
}
|
}
|
||||||
|
|
||||||
// key
|
// key
|
||||||
$dkim_txt .= 'k=rsa;p=' . trim(preg_replace('/-----BEGIN PUBLIC KEY-----(.+)-----END PUBLIC KEY-----/s', '$1', str_replace("\n", '', $domain['dkim_pubkey']))) . ';';
|
$dkim_txt .= 'k=rsa;p=' . trim(preg_replace('/-----BEGIN PUBLIC KEY-----(.+)-----END PUBLIC KEY-----/s',
|
||||||
|
'$1', str_replace("\n", '', $domain['dkim_pubkey']))) . ';';
|
||||||
|
|
||||||
// service-type
|
// service-type
|
||||||
if (Settings::Get('dkim.dkim_servicetype') == '1') {
|
if (Settings::Get('dkim.dkim_servicetype') == '1') {
|
||||||
@@ -503,10 +571,15 @@ class Dns
|
|||||||
return $zone_dkim;
|
return $zone_dkim;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function encloseTXTContent($txt_content, $isMultiLine = false)
|
/**
|
||||||
|
* @param string $txt_content
|
||||||
|
* @param bool $isMultiLine
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function encloseTXTContent(string $txt_content, bool $isMultiLine = false): string
|
||||||
{
|
{
|
||||||
// check that TXT content is enclosed in " "
|
// check that TXT content is enclosed in " "
|
||||||
if ($isMultiLine == false && Settings::Get('system.dns_server') != 'PowerDNS') {
|
if (!$isMultiLine && Settings::Get('system.dns_server') != 'PowerDNS') {
|
||||||
if (substr($txt_content, 0, 1) != '"') {
|
if (substr($txt_content, 0, 1) != '"') {
|
||||||
$txt_content = '"' . $txt_content;
|
$txt_content = '"' . $txt_content;
|
||||||
}
|
}
|
||||||
@@ -526,10 +599,13 @@ class Dns
|
|||||||
return $txt_content;
|
return $txt_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function escapeSoaAdminMail($email)
|
/**
|
||||||
|
* @param string $email
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private static function escapeSoaAdminMail(string $email): string
|
||||||
{
|
{
|
||||||
$mail_parts = explode("@", $email);
|
$mail_parts = explode("@", $email);
|
||||||
$escpd_mail = str_replace(".", "\.", $mail_parts[0]) . "." . $mail_parts[1] . ".";
|
return str_replace(".", "\.", $mail_parts[0]) . "." . $mail_parts[1] . ".";
|
||||||
return $escpd_mail;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,14 +29,22 @@ use Froxlor\Settings;
|
|||||||
|
|
||||||
class DnsEntry
|
class DnsEntry
|
||||||
{
|
{
|
||||||
public $record;
|
public string $record;
|
||||||
public $ttl;
|
public int $ttl;
|
||||||
public $class = 'IN';
|
public string $class = 'IN';
|
||||||
public $type;
|
public string $type;
|
||||||
public $priority;
|
public int $priority;
|
||||||
public $content;
|
public ?string $content;
|
||||||
|
|
||||||
public function __construct($record = '', $type = 'A', $content = null, $prio = 0, $ttl = 0, $class = 'IN')
|
/**
|
||||||
|
* @param string $record
|
||||||
|
* @param string $type
|
||||||
|
* @param string|null $content
|
||||||
|
* @param int $prio
|
||||||
|
* @param int $ttl
|
||||||
|
* @param string $class
|
||||||
|
*/
|
||||||
|
public function __construct(string $record = '', string $type = 'A', string $content = null, int $prio = 0, int $ttl = 0, string $class = 'IN')
|
||||||
{
|
{
|
||||||
$this->record = $record;
|
$this->record = $record;
|
||||||
$this->type = $type;
|
$this->type = $type;
|
||||||
@@ -72,7 +80,6 @@ class DnsEntry
|
|||||||
// last line
|
// last line
|
||||||
$_content .= "\t\t\t\t" . '"' . $_l . '")';
|
$_content .= "\t\t\t\t" . '"' . $_l . '")';
|
||||||
}
|
}
|
||||||
$result = $this->record . "\t" . $this->ttl . "\t" . $this->class . "\t" . $this->type . "\t" . (($this->priority >= 0 && ($this->type == 'MX' || $this->type == 'SRV')) ? $this->priority . "\t" : "") . $_content . PHP_EOL;
|
return $this->record . "\t" . $this->ttl . "\t" . $this->class . "\t" . $this->type . "\t" . (($this->priority >= 0 && ($this->type == 'MX' || $this->type == 'SRV')) ? $this->priority . "\t" : "") . $_content . PHP_EOL;
|
||||||
return $result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,12 +29,18 @@ use Froxlor\Settings;
|
|||||||
|
|
||||||
class DnsZone
|
class DnsZone
|
||||||
{
|
{
|
||||||
public $ttl;
|
public int $ttl;
|
||||||
public $origin;
|
public string $origin;
|
||||||
public $serial;
|
public string $serial;
|
||||||
public $records;
|
public ?array $records;
|
||||||
|
|
||||||
public function __construct($ttl = 0, $origin = '', $serial = '', $records = null)
|
/**
|
||||||
|
* @param int $ttl
|
||||||
|
* @param string $origin
|
||||||
|
* @param string $serial
|
||||||
|
* @param array|null $records
|
||||||
|
*/
|
||||||
|
public function __construct(int $ttl = 0, string $origin = '', string $serial = '', array $records = null)
|
||||||
{
|
{
|
||||||
$this->ttl = ($ttl <= 0 ? Settings::Get('system.defaultttl') : $ttl);
|
$this->ttl = ($ttl <= 0 ? Settings::Get('system.defaultttl') : $ttl);
|
||||||
$this->origin = $origin;
|
$this->origin = $origin;
|
||||||
@@ -44,13 +50,13 @@ class DnsZone
|
|||||||
|
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
$_zonefile = "\$TTL " . $this->ttl . PHP_EOL;
|
$zone_file = "\$TTL " . $this->ttl . PHP_EOL;
|
||||||
$_zonefile .= "\$ORIGIN " . $this->origin . "." . PHP_EOL;
|
$zone_file .= "\$ORIGIN " . $this->origin . "." . PHP_EOL;
|
||||||
if (!empty($this->records)) {
|
if (!empty($this->records)) {
|
||||||
foreach ($this->records as $record) {
|
foreach ($this->records as $record) {
|
||||||
$_zonefile .= (string)$record;
|
$zone_file .= (string)$record;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $_zonefile;
|
return $zone_file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,18 +37,18 @@ class PowerDNS
|
|||||||
/**
|
/**
|
||||||
* remove all records and entries of a given domain
|
* remove all records and entries of a given domain
|
||||||
*
|
*
|
||||||
* @param array $domain
|
* @param string|null $domain
|
||||||
*/
|
*/
|
||||||
public static function cleanDomainZone($domain = null)
|
public static function cleanDomainZone(string $domain = null)
|
||||||
{
|
{
|
||||||
if (is_array($domain) && isset($domain['domain'])) {
|
if (!empty($domain)) {
|
||||||
$pdns_domains_stmt = self::getDB()->prepare("SELECT `id`, `name` FROM `domains` WHERE `name` = :domain");
|
$pdns_domains_stmt = self::getDB()->prepare("SELECT `id`, `name` FROM `domains` WHERE `name` = :domain");
|
||||||
$del_rec_stmt = self::getDB()->prepare("DELETE FROM `records` WHERE `domain_id` = :did");
|
$del_rec_stmt = self::getDB()->prepare("DELETE FROM `records` WHERE `domain_id` = :did");
|
||||||
$del_meta_stmt = self::getDB()->prepare("DELETE FROM `domainmetadata` WHERE `domain_id` = :did");
|
$del_meta_stmt = self::getDB()->prepare("DELETE FROM `domainmetadata` WHERE `domain_id` = :did");
|
||||||
$del_dom_stmt = self::getDB()->prepare("DELETE FROM `domains` WHERE `id` = :did");
|
$del_dom_stmt = self::getDB()->prepare("DELETE FROM `domains` WHERE `id` = :did");
|
||||||
|
|
||||||
$pdns_domains_stmt->execute([
|
$pdns_domains_stmt->execute([
|
||||||
'domain' => $domain['domain']
|
'domain' => $domain
|
||||||
]);
|
]);
|
||||||
$pdns_domain = $pdns_domains_stmt->fetch(PDO::FETCH_ASSOC);
|
$pdns_domain = $pdns_domains_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
@@ -67,16 +67,19 @@ class PowerDNS
|
|||||||
/**
|
/**
|
||||||
* get pdo database connection to powerdns database
|
* get pdo database connection to powerdns database
|
||||||
*
|
*
|
||||||
* @return PDO
|
* @return \PDO
|
||||||
*/
|
*/
|
||||||
public static function getDB()
|
public static function getDB(): \PDO
|
||||||
{
|
{
|
||||||
if (!isset(self::$pdns_db) || (self::$pdns_db instanceof PDO) == false) {
|
if (!isset(self::$pdns_db) || !(self::$pdns_db instanceof PDO)) {
|
||||||
self::connectToPdnsDb();
|
self::connectToPdnsDb();
|
||||||
}
|
}
|
||||||
return self::$pdns_db;
|
return self::$pdns_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
private static function connectToPdnsDb()
|
private static function connectToPdnsDb()
|
||||||
{
|
{
|
||||||
// get froxlor pdns config
|
// get froxlor pdns config
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ class Domain
|
|||||||
*
|
*
|
||||||
* @param int $domain_id
|
* @param int $domain_id
|
||||||
* @return array
|
* @return array
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function getIpsOfDomain($domain_id)
|
public static function getIpsOfDomain(int $domain_id = 0): array
|
||||||
{
|
{
|
||||||
if ($domain_id > 0) {
|
if ($domain_id > 0) {
|
||||||
$sel_stmt = Database::prepare("
|
$sel_stmt = Database::prepare("
|
||||||
@@ -75,7 +76,7 @@ class Domain
|
|||||||
*
|
*
|
||||||
* @return array array of enabled redirect-codes
|
* @return array array of enabled redirect-codes
|
||||||
*/
|
*/
|
||||||
public static function getRedirectCodesArray()
|
public static function getRedirectCodesArray(): array
|
||||||
{
|
{
|
||||||
$sql = "SELECT * FROM `" . TABLE_PANEL_REDIRECTCODES . "` WHERE `enabled` = '1' ORDER BY `id` ASC";
|
$sql = "SELECT * FROM `" . TABLE_PANEL_REDIRECTCODES . "` WHERE `enabled` = '1' ORDER BY `id` ASC";
|
||||||
$result_stmt = Database::query($sql);
|
$result_stmt = Database::query($sql);
|
||||||
@@ -92,12 +93,12 @@ class Domain
|
|||||||
* returns the redirect-code for a given
|
* returns the redirect-code for a given
|
||||||
* domain-id
|
* domain-id
|
||||||
*
|
*
|
||||||
* @param integer $domainid
|
* @param int $domainid id of the domain
|
||||||
* id of the domain
|
|
||||||
*
|
*
|
||||||
* @return string redirect-code
|
* @return string redirect-code
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function getDomainRedirectCode($domainid = 0)
|
public static function getDomainRedirectCode(int $domainid = 0): string
|
||||||
{
|
{
|
||||||
// get system default
|
// get system default
|
||||||
$default = '301';
|
$default = '301';
|
||||||
@@ -128,12 +129,11 @@ class Domain
|
|||||||
* return an array of all enabled redirect-codes
|
* return an array of all enabled redirect-codes
|
||||||
* for the settings form
|
* for the settings form
|
||||||
*
|
*
|
||||||
* @param bool $add_desc
|
* @param bool $add_desc optional, default true, add the code-description
|
||||||
* optional, default true, add the code-description
|
|
||||||
*
|
*
|
||||||
* @return array array of enabled redirect-codes
|
* @return array array of enabled redirect-codes
|
||||||
*/
|
*/
|
||||||
public static function getRedirectCodes($add_desc = true)
|
public static function getRedirectCodes(bool $add_desc = true): array
|
||||||
{
|
{
|
||||||
$sql = "SELECT * FROM `" . TABLE_PANEL_REDIRECTCODES . "` WHERE `enabled` = '1' ORDER BY `id` ASC";
|
$sql = "SELECT * FROM `" . TABLE_PANEL_REDIRECTCODES . "` WHERE `enabled` = '1' ORDER BY `id` ASC";
|
||||||
$result_stmt = Database::query($sql);
|
$result_stmt = Database::query($sql);
|
||||||
@@ -153,12 +153,12 @@ class Domain
|
|||||||
* returns the redirect-id for a given
|
* returns the redirect-id for a given
|
||||||
* domain-id
|
* domain-id
|
||||||
*
|
*
|
||||||
* @param integer $domainid
|
* @param int $domainid id of the domain
|
||||||
* id of the domain
|
|
||||||
*
|
*
|
||||||
* @return integer redirect-code-id
|
* @return int redirect-code-id
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function getDomainRedirectId($domainid = 0)
|
public static function getDomainRedirectId(int $domainid = 0): int
|
||||||
{
|
{
|
||||||
$code = 1;
|
$code = 1;
|
||||||
if ($domainid > 0) {
|
if ($domainid > 0) {
|
||||||
@@ -171,7 +171,7 @@ class Domain
|
|||||||
'domainid' => $domainid
|
'domainid' => $domainid
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (is_array($result) && isset($result['redirect'])) {
|
if ($result && isset($result['redirect'])) {
|
||||||
$code = (int)$result['redirect'];
|
$code = (int)$result['redirect'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,16 +179,15 @@ class Domain
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* adds a redirectcode for a domain
|
* adds a redirect-code for a domain
|
||||||
*
|
*
|
||||||
* @param integer $domainid
|
* @param int $domainid id of the domain to add the code for
|
||||||
* id of the domain to add the code for
|
* @param int $redirect selected redirect-id
|
||||||
* @param integer $redirect
|
|
||||||
* selected redirect-id
|
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function addRedirectToDomain($domainid = 0, $redirect = 1)
|
public static function addRedirectToDomain(int $domainid = 0, int $redirect = 1)
|
||||||
{
|
{
|
||||||
if ($domainid > 0) {
|
if ($domainid > 0) {
|
||||||
$ins_stmt = Database::prepare("
|
$ins_stmt = Database::prepare("
|
||||||
@@ -202,19 +201,18 @@ class Domain
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* updates the redirectcode of a domain
|
* updates the redirect-code of a domain
|
||||||
* if redirect-code is false, nothing happens
|
* if redirect-code is false, nothing happens
|
||||||
*
|
*
|
||||||
* @param integer $domainid
|
* @param int $domainid id of the domain to update
|
||||||
* id of the domain to update
|
* @param int $redirect selected redirect-id
|
||||||
* @param integer $redirect
|
|
||||||
* selected redirect-id or false
|
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function updateRedirectOfDomain($domainid = 0, $redirect = false)
|
public static function updateRedirectOfDomain(int $domainid = 0, int $redirect = 0)
|
||||||
{
|
{
|
||||||
if ($redirect == false) {
|
if (!$redirect) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,12 +238,12 @@ class Domain
|
|||||||
* check whether a domain has subdomains added as full-domains
|
* check whether a domain has subdomains added as full-domains
|
||||||
* #329
|
* #329
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id domain-id
|
||||||
* domain-id
|
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function domainHasMainSubDomains($id = 0)
|
public static function domainHasMainSubDomains(int $id): bool
|
||||||
{
|
{
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT COUNT(`id`) as `mainsubs` FROM `" . TABLE_PANEL_DOMAINS . "`
|
SELECT COUNT(`id`) as `mainsubs` FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
@@ -254,8 +252,8 @@ class Domain
|
|||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (isset($result['mainsubs']) && $result['mainsubs'] > 0) {
|
if ($result && isset($result['mainsubs'])) {
|
||||||
return true;
|
return $result['mainsubs'] > 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -264,12 +262,12 @@ class Domain
|
|||||||
* check whether a subof-domain exists
|
* check whether a subof-domain exists
|
||||||
* #329
|
* #329
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id subof-domain-id
|
||||||
* subof-domain-id
|
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function domainMainToSubExists($id = 0)
|
public static function domainMainToSubExists(int $id): bool
|
||||||
{
|
{
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `id` = :id");
|
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `id` = :id");
|
||||||
@@ -278,8 +276,8 @@ class Domain
|
|||||||
]);
|
]);
|
||||||
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
|
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (isset($result['id']) && $result['id'] > 0) {
|
if ($result && isset($result['id'])) {
|
||||||
return true;
|
return $result['id'] > 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -289,9 +287,10 @@ class Domain
|
|||||||
*
|
*
|
||||||
* @param int $domainid
|
* @param int $domainid
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function domainHasSslIpPort($domainid = 0)
|
public static function domainHasSslIpPort(int $domainid): bool
|
||||||
{
|
{
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT `dt`.* FROM `" . TABLE_DOMAINTOIP . "` `dt`, `" . TABLE_PANEL_IPSANDPORTS . "` `iap`
|
SELECT `dt`.* FROM `" . TABLE_DOMAINTOIP . "` `dt`, `" . TABLE_PANEL_IPSANDPORTS . "` `iap`
|
||||||
@@ -301,7 +300,7 @@ class Domain
|
|||||||
]);
|
]);
|
||||||
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
|
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (is_array($result) && isset($result['id_ipandports'])) {
|
if ($result && isset($result['id_ipandports'])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -311,12 +310,12 @@ class Domain
|
|||||||
* returns true or false whether a given domain id
|
* returns true or false whether a given domain id
|
||||||
* is the std-subdomain of a customer
|
* is the std-subdomain of a customer
|
||||||
*
|
*
|
||||||
* @param
|
* @param int $did domain-id
|
||||||
* int domain-id
|
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function isCustomerStdSubdomain($did = 0)
|
public static function isCustomerStdSubdomain(int $did): bool
|
||||||
{
|
{
|
||||||
if ($did > 0) {
|
if ($did > 0) {
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
@@ -327,21 +326,31 @@ class Domain
|
|||||||
'did' => $did
|
'did' => $did
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (is_array($result) && isset($result['customerid']) && $result['customerid'] > 0) {
|
if ($result && isset($result['customerid'])) {
|
||||||
return true;
|
return $result['customerid'] > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function triggerLetsEncryptCSRForAliasDestinationDomain($aliasDestinationDomainID, $log)
|
/**
|
||||||
{
|
* @param int $aliasDestinationDomainID
|
||||||
if (isset($aliasDestinationDomainID) && $aliasDestinationDomainID > 0) {
|
* @param FroxlorLogger $log
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "LetsEncrypt CSR triggered for domain ID " . $aliasDestinationDomainID);
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function triggerLetsEncryptCSRForAliasDestinationDomain(
|
||||||
|
int $aliasDestinationDomainID,
|
||||||
|
FroxlorLogger $log
|
||||||
|
) {
|
||||||
|
if ($aliasDestinationDomainID > 0) {
|
||||||
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO,
|
||||||
|
"LetsEncrypt CSR triggered for domain ID " . $aliasDestinationDomainID);
|
||||||
$upd_stmt = Database::prepare("UPDATE
|
$upd_stmt = Database::prepare("UPDATE
|
||||||
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
||||||
SET
|
SET
|
||||||
`expirationdate` = null
|
`validtodate` = null
|
||||||
WHERE
|
WHERE
|
||||||
domainid = :domainid
|
domainid = :domainid
|
||||||
");
|
");
|
||||||
@@ -351,7 +360,11 @@ class Domain
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function doLetsEncryptCleanUp($domainname = null)
|
/**
|
||||||
|
* @param string $domainname
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
public static function doLetsEncryptCleanUp(string $domainname): bool
|
||||||
{
|
{
|
||||||
// @ see \Froxlor\Cron\Http\LetsEncrypt\AcmeSh.php
|
// @ see \Froxlor\Cron\Http\LetsEncrypt\AcmeSh.php
|
||||||
$acmesh = AcmeSh::getAcmeSh();
|
$acmesh = AcmeSh::getAcmeSh();
|
||||||
@@ -374,18 +387,19 @@ class Domain
|
|||||||
/**
|
/**
|
||||||
* checks give path for security issues
|
* checks give path for security issues
|
||||||
* and returns a string that can be appended
|
* and returns a string that can be appended
|
||||||
* to a line for a open_basedir directive
|
* to a line for an open_basedir directive
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path the path to check and append
|
||||||
* the path to check and append
|
* @param bool $first if true, no ':' will be prefixed to the path
|
||||||
* @param boolean $first
|
|
||||||
* if true, no ':' will be prefixed to the path
|
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function appendOpenBasedirPath($path = '', $first = false)
|
public static function appendOpenBasedirPath(string $path = '', bool $first = false): string
|
||||||
{
|
{
|
||||||
if ($path != '' && $path != '/' && (!preg_match("#^/dev#i", $path) || preg_match("#^/dev/urandom#i", $path)) && !preg_match("#^/proc#i", $path) && !preg_match("#^/etc#i", $path) && !preg_match("#^/sys#i", $path) && !preg_match("#:#", $path)) {
|
if ($path != '' && $path != '/' && (!preg_match("#^/dev#i", $path) || preg_match("#^/dev/urandom#i",
|
||||||
|
$path)) && !preg_match("#^/proc#i", $path) && !preg_match("#^/etc#i",
|
||||||
|
$path) && !preg_match("#^/sys#i", $path) && !preg_match("#:#", $path)) {
|
||||||
if (preg_match("#^/dev/urandom#i", $path)) {
|
if (preg_match("#^/dev/urandom#i", $path)) {
|
||||||
$path = FileDir::makeCorrectFile($path);
|
$path = FileDir::makeCorrectFile($path);
|
||||||
} else {
|
} else {
|
||||||
@@ -394,7 +408,7 @@ class Domain
|
|||||||
|
|
||||||
// check for php-version that requires the trailing
|
// check for php-version that requires the trailing
|
||||||
// slash to be removed as it does not allow the usage
|
// slash to be removed as it does not allow the usage
|
||||||
// of the subfolders within the given folder, fixes #797
|
// of the sub-folders within the given folder, fixes #797
|
||||||
if ((PHP_MINOR_VERSION == 2 && PHP_VERSION_ID >= 50216) || PHP_VERSION_ID >= 50304) {
|
if ((PHP_MINOR_VERSION == 2 && PHP_VERSION_ID >= 50216) || PHP_VERSION_ID >= 50304) {
|
||||||
// check trailing slash
|
// check trailing slash
|
||||||
if (substr($path, -1, 1) == '/') {
|
if (substr($path, -1, 1) == '/') {
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ use PDO;
|
|||||||
|
|
||||||
class IpAddr
|
class IpAddr
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
public static function getIpAddresses()
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getIpAddresses(): array
|
||||||
{
|
{
|
||||||
$result_stmt = Database::query("
|
$result_stmt = Database::query("
|
||||||
SELECT `id`, `ip`, `port` FROM `" . TABLE_PANEL_IPSANDPORTS . "` ORDER BY `ip` ASC, `port` ASC
|
SELECT `id`, `ip`, `port` FROM `" . TABLE_PANEL_IPSANDPORTS . "` ORDER BY `ip` ASC, `port` ASC
|
||||||
@@ -51,14 +53,22 @@ class IpAddr
|
|||||||
return $system_ipaddress_array;
|
return $system_ipaddress_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getSslIpPortCombinations()
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getSslIpPortCombinations(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'' => lng('panel.none_value')
|
'' => lng('panel.none_value')
|
||||||
] + self::getIpPortCombinations(true);
|
] + self::getIpPortCombinations(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getIpPortCombinations($ssl = false)
|
/**
|
||||||
|
* @param bool $ssl
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function getIpPortCombinations(bool $ssl = false): array
|
||||||
{
|
{
|
||||||
global $userinfo;
|
global $userinfo;
|
||||||
|
|
||||||
|
|||||||
@@ -38,30 +38,24 @@ class FileDir
|
|||||||
* which had to be created below with correct Owner/Group
|
* which had to be created below with correct Owner/Group
|
||||||
* (Copied from cron_tasks.php:rev1189 as we'll need this more often in future)
|
* (Copied from cron_tasks.php:rev1189 as we'll need this more often in future)
|
||||||
*
|
*
|
||||||
* @param string $homeDir
|
* @param string $homeDir The homedir of the user
|
||||||
* The homedir of the user
|
* @param string $dirToCreate The dir which should be created
|
||||||
* @param string $dirToCreate
|
* @param int $uid The uid of the user
|
||||||
* The dir which should be created
|
* @param int $gid The gid of the user
|
||||||
* @param int $uid
|
* @param bool $placeindex Place standard-index.html into the new folder
|
||||||
* The uid of the user
|
* @param bool $allow_notwithinhomedir Allow creating a directory out of the customers docroot
|
||||||
* @param int $gid
|
|
||||||
* The gid of the user
|
|
||||||
* @param bool $placeindex
|
|
||||||
* Place standard-index.html into the new folder
|
|
||||||
* @param bool $allow_notwithinhomedir
|
|
||||||
* Allow creating a directory out of the customers docroot
|
|
||||||
*
|
*
|
||||||
* @return bool true if everything went okay, false if something went wrong
|
* @return bool true if everything went okay, false if something went wrong
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function mkDirWithCorrectOwnership(
|
public static function mkDirWithCorrectOwnership(
|
||||||
$homeDir,
|
string $homeDir,
|
||||||
$dirToCreate,
|
string $dirToCreate,
|
||||||
$uid,
|
int $uid,
|
||||||
$gid,
|
int $gid,
|
||||||
$placeindex = false,
|
bool $placeindex = false,
|
||||||
$allow_notwithinhomedir = false
|
bool $allow_notwithinhomedir = false
|
||||||
) {
|
): bool {
|
||||||
if ($homeDir != '' && $dirToCreate != '') {
|
if ($homeDir != '' && $dirToCreate != '') {
|
||||||
$homeDir = self::makeCorrectDir($homeDir);
|
$homeDir = self::makeCorrectDir($homeDir);
|
||||||
$dirToCreate = self::makeCorrectDir($dirToCreate);
|
$dirToCreate = self::makeCorrectDir($dirToCreate);
|
||||||
@@ -116,15 +110,14 @@ class FileDir
|
|||||||
* Function which returns a correct dirname, means to add slashes at the beginning and at the end if there weren't
|
* Function which returns a correct dirname, means to add slashes at the beginning and at the end if there weren't
|
||||||
* some
|
* some
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $dir the path to correct
|
||||||
* the path to correct
|
|
||||||
*
|
*
|
||||||
* @return string the corrected path
|
* @return string the corrected path
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function makeCorrectDir($dir)
|
public static function makeCorrectDir(string $dir): string
|
||||||
{
|
{
|
||||||
if (is_string($dir) && strlen($dir) > 0) {
|
if (strlen($dir) > 0) {
|
||||||
$dir = trim($dir);
|
$dir = trim($dir);
|
||||||
if (substr($dir, -1, 1) != '/') {
|
if (substr($dir, -1, 1) != '/') {
|
||||||
$dir .= '/';
|
$dir .= '/';
|
||||||
@@ -140,16 +133,15 @@ class FileDir
|
|||||||
/**
|
/**
|
||||||
* Function which returns a secure path, means to remove all multiple dots and slashes
|
* Function which returns a secure path, means to remove all multiple dots and slashes
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path the path to secure
|
||||||
* the path to secure
|
|
||||||
*
|
*
|
||||||
* @return string the corrected path
|
* @return string the corrected path
|
||||||
*/
|
*/
|
||||||
public static function makeSecurePath($path)
|
public static function makeSecurePath(string $path): string
|
||||||
{
|
{
|
||||||
// check for bad characters, some are allowed with escaping
|
// check for bad characters, some are allowed with escaping,
|
||||||
// but we generally don't want them in our directory-names,
|
// but we generally don't want them in our directory-names,
|
||||||
// thx to aaronmueller for this snipped
|
// thx to aaronmueller for this snippet
|
||||||
$badchars = [
|
$badchars = [
|
||||||
':',
|
':',
|
||||||
';',
|
';',
|
||||||
@@ -161,7 +153,11 @@ class FileDir
|
|||||||
'$',
|
'$',
|
||||||
'~',
|
'~',
|
||||||
'?',
|
'?',
|
||||||
"\0"
|
"\0",
|
||||||
|
"\n",
|
||||||
|
"\r",
|
||||||
|
"\t",
|
||||||
|
"\f"
|
||||||
];
|
];
|
||||||
foreach ($badchars as $bc) {
|
foreach ($badchars as $bc) {
|
||||||
$path = str_replace($bc, "", $path);
|
$path = str_replace($bc, "", $path);
|
||||||
@@ -187,16 +183,13 @@ class FileDir
|
|||||||
/**
|
/**
|
||||||
* Wrapper around the exec command.
|
* Wrapper around the exec command.
|
||||||
*
|
*
|
||||||
* @param string $exec_string
|
* @param string $exec_string command to be executed
|
||||||
* command to be executed
|
* @param mixed $return_value referenced variable where the output is stored
|
||||||
* @param string $return_value
|
* @param ?array $allowedChars optional array of allowed characters in path/command
|
||||||
* referenced variable where the output is stored
|
|
||||||
* @param array $allowedChars
|
|
||||||
* optional array of allowed characters in path/command
|
|
||||||
*
|
*
|
||||||
* @return array result of exec()
|
* @return array result of exec()
|
||||||
*/
|
*/
|
||||||
public static function safe_exec($exec_string, &$return_value = false, $allowedChars = null)
|
public static function safe_exec(string $exec_string, &$return_value = false, $allowedChars = null)
|
||||||
{
|
{
|
||||||
$disallowed = [
|
$disallowed = [
|
||||||
';',
|
';',
|
||||||
@@ -241,19 +234,20 @@ class FileDir
|
|||||||
/**
|
/**
|
||||||
* store the default index-file in a given destination folder
|
* store the default index-file in a given destination folder
|
||||||
*
|
*
|
||||||
* @param string $loginname
|
* @param string $loginname customers loginname
|
||||||
* customers loginname
|
* @param string $destination path where to create the file
|
||||||
* @param string $destination
|
* @param object $logger FroxlorLogger object
|
||||||
* path where to create the file
|
* @param bool $force force creation whatever the settings say (needed for task #2, create new user)
|
||||||
* @param object $logger
|
|
||||||
* FroxlorLogger object
|
|
||||||
* @param boolean $force
|
|
||||||
* force creation whatever the settings say (needed for task #2, create new user)
|
|
||||||
*
|
*
|
||||||
* @return null
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function storeDefaultIndex($loginname = null, $destination = null, $logger = null, $force = false)
|
public static function storeDefaultIndex(
|
||||||
{
|
string $loginname,
|
||||||
|
string $destination,
|
||||||
|
$logger = null,
|
||||||
|
bool $force = false
|
||||||
|
) {
|
||||||
if ($force || (int)Settings::Get('system.store_index_file_subs') == 1) {
|
if ($force || (int)Settings::Get('system.store_index_file_subs') == 1) {
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT `t`.`value`, `c`.`email` AS `customer_email`, `a`.`email` AS `admin_email`, `c`.`loginname` AS `customer_login`, `a`.`loginname` AS `admin_login`
|
SELECT `t`.`value`, `c`.`email` AS `customer_email`, `a`.`email` AS `admin_email`, `c`.`loginname` AS `customer_login`, `a`.`loginname` AS `admin_login`
|
||||||
@@ -302,18 +296,16 @@ class FileDir
|
|||||||
self::safe_exec('cp -a ' . Froxlor::getInstallDir() . '/templates/misc/standardcustomer/* ' . escapeshellarg($destination));
|
self::safe_exec('cp -a ' . Froxlor::getInstallDir() . '/templates/misc/standardcustomer/* ' . escapeshellarg($destination));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function which returns a correct filename, means to add a slash at the beginning if there wasn't one
|
* Function which returns a correct filename, means to add a slash at the beginning if there wasn't one
|
||||||
*
|
*
|
||||||
* @param string $filename
|
* @param string $filename the filename
|
||||||
* the filename
|
|
||||||
*
|
*
|
||||||
* @return string the corrected filename
|
* @return string the corrected filename
|
||||||
*/
|
*/
|
||||||
public static function makeCorrectFile(string $filename)
|
public static function makeCorrectFile(string $filename): string
|
||||||
{
|
{
|
||||||
if (trim($filename) == '') {
|
if (trim($filename) == '') {
|
||||||
$error = 'Given filename for function ' . __FUNCTION__ . ' is empty.' . "\n";
|
$error = 'Given filename for function ' . __FUNCTION__ . ' is empty.' . "\n";
|
||||||
@@ -329,21 +321,19 @@ class FileDir
|
|||||||
$filename = '/' . $filename;
|
$filename = '/' . $filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
$filename = self::makeSecurePath($filename);
|
return self::makeSecurePath($filename);
|
||||||
return $filename;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* checks a directory against disallowed paths which could
|
* checks a directory against disallowed paths which could
|
||||||
* lead to a damaged system if you use them
|
* lead to a damaged system if you use them
|
||||||
*
|
*
|
||||||
* @param string $fieldname
|
* @param string|null $path
|
||||||
* @param array $fielddata
|
|
||||||
* @param mixed $newfieldvalue
|
|
||||||
*
|
*
|
||||||
* @return boolean|array
|
* @return bool
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function checkDisallowedPaths($path = null)
|
public static function checkDisallowedPaths(string $path): bool
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* disallow base-directories and /
|
* disallow base-directories and /
|
||||||
@@ -381,12 +371,11 @@ class FileDir
|
|||||||
/**
|
/**
|
||||||
* Function which returns a correct destination for Postfix Virtual Table
|
* Function which returns a correct destination for Postfix Virtual Table
|
||||||
*
|
*
|
||||||
* @param
|
* @param string $destination The destinations
|
||||||
* string The destinations
|
*
|
||||||
* @return string the corrected destinations
|
* @return string the corrected destinations
|
||||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
|
||||||
*/
|
*/
|
||||||
public static function makeCorrectDestination($destination)
|
public static function makeCorrectDestination(string $destination): string
|
||||||
{
|
{
|
||||||
$search = '/ +/';
|
$search = '/ +/';
|
||||||
$replace = ' ';
|
$replace = ' ';
|
||||||
@@ -406,27 +395,25 @@ class FileDir
|
|||||||
/**
|
/**
|
||||||
* Returns a valid html tag for the chosen $fieldType for paths
|
* Returns a valid html tag for the chosen $fieldType for paths
|
||||||
*
|
*
|
||||||
* @param
|
* @param string $path The path to start searching in
|
||||||
* string path The path to start searching in
|
* @param int $uid The uid which must match the found directories
|
||||||
* @param
|
* @param int $gid The gid which must match the found directories
|
||||||
* integer uid The uid which must match the found directories
|
* @param string $value the value for the input-field
|
||||||
* @param
|
* @param bool $dom
|
||||||
* integer gid The gid which must match the found directories
|
|
||||||
* @param
|
|
||||||
* string value the value for the input-field
|
|
||||||
*
|
*
|
||||||
* @return string The html tag for the chosen $fieldType
|
* @return array
|
||||||
*
|
*
|
||||||
* @author Martin Burchert <martin.burchert@syscp.de>
|
* @throws Exception
|
||||||
* @author Manuel Bernhardt <manuel.bernhardt@syscp.de>
|
* @author Manuel Bernhardt <manuel.bernhardt@syscp.de>
|
||||||
|
* @author Martin Burchert <martin.burchert@syscp.de>
|
||||||
*/
|
*/
|
||||||
public static function makePathfield($path, $uid, $gid, $value = '', $dom = false)
|
public static function makePathfield(string $path, int $uid, int $gid, string $value = '', bool $dom = false): array
|
||||||
{
|
{
|
||||||
$value = str_replace($path, '', $value);
|
$value = str_replace($path, '', $value);
|
||||||
$field = [];
|
$field = [];
|
||||||
|
|
||||||
// path is given without starting slash
|
// path is given without starting slash
|
||||||
// but dirList holds the paths with starting slash
|
// but dirList holds the paths with starting slash,
|
||||||
// so we just add one here to get the correct
|
// so we just add one here to get the correct
|
||||||
// default path selected, #225
|
// default path selected, #225
|
||||||
if (substr($value, 0, 1) != '/' && !$dom) {
|
if (substr($value, 0, 1) != '/' && !$dom) {
|
||||||
@@ -460,7 +447,8 @@ class FileDir
|
|||||||
$field = [
|
$field = [
|
||||||
'type' => 'select',
|
'type' => 'select',
|
||||||
'select_var' => $_field,
|
'select_var' => $_field,
|
||||||
'selected' => $value
|
'selected' => $value,
|
||||||
|
'value' => $value
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
$field = [
|
$field = [
|
||||||
@@ -480,16 +468,14 @@ class FileDir
|
|||||||
* This function checks every found directory if they match either $uid or $gid, if they do
|
* This function checks every found directory if they match either $uid or $gid, if they do
|
||||||
* the found directory is valid. It uses recursive-iterators to find subdirectories.
|
* the found directory is valid. It uses recursive-iterators to find subdirectories.
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path the path to start searching in
|
||||||
* the path to start searching in
|
* @param int $uid the uid which must match the found directories
|
||||||
* @param int $uid
|
* @param int $gid the gid which must match the found directories
|
||||||
* the uid which must match the found directories
|
|
||||||
* @param int $gid
|
|
||||||
* the gid which must match the found directories
|
|
||||||
*
|
*
|
||||||
* @return array Array of found valid paths
|
* @return array Array of found valid paths
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private static function findDirs($path, $uid, $gid)
|
private static function findDirs(string $path, int $uid, int $gid): array
|
||||||
{
|
{
|
||||||
$_fileList = [];
|
$_fileList = [];
|
||||||
$path = self::makeCorrectDir($path);
|
$path = self::makeCorrectDir($path);
|
||||||
@@ -499,7 +485,8 @@ class FileDir
|
|||||||
// Will exclude everything under these directories
|
// Will exclude everything under these directories
|
||||||
$exclude = [
|
$exclude = [
|
||||||
'awstats',
|
'awstats',
|
||||||
'webalizer'
|
'webalizer',
|
||||||
|
'goaccess'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -565,7 +552,7 @@ class FileDir
|
|||||||
*
|
*
|
||||||
* @return string functionname + parameter (not the file)
|
* @return string functionname + parameter (not the file)
|
||||||
*/
|
*/
|
||||||
private static function getImmutableFunction(bool $remove = false)
|
private static function getImmutableFunction(bool $remove = false): string
|
||||||
{
|
{
|
||||||
if (self::isFreeBSD()) {
|
if (self::isFreeBSD()) {
|
||||||
// FreeBSD style
|
// FreeBSD style
|
||||||
@@ -585,7 +572,7 @@ class FileDir
|
|||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function isFreeBSD(bool $exact = false)
|
public static function isFreeBSD(bool $exact = false): bool
|
||||||
{
|
{
|
||||||
if (($exact && PHP_OS == 'FreeBSD') || (!$exact && stristr(PHP_OS, 'BSD'))) {
|
if (($exact && PHP_OS == 'FreeBSD') || (!$exact && stristr(PHP_OS, 'BSD'))) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ final class Froxlor
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Main version variable
|
// Main version variable
|
||||||
const VERSION = '2.0.2';
|
const VERSION = '2.0.16';
|
||||||
|
|
||||||
// Database version (YYYYMMDDC where C is a daily counter)
|
// Database version (YYYYMMDDC where C is a daily counter)
|
||||||
const DBVERSION = '202212060';
|
const DBVERSION = '202304260';
|
||||||
|
|
||||||
// Distribution branding-tag (used for Debian etc.)
|
// Distribution branding-tag (used for Debian etc.)
|
||||||
const BRANDING = '';
|
const BRANDING = '';
|
||||||
@@ -45,7 +45,7 @@ final class Froxlor
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function getInstallDir()
|
public static function getInstallDir(): string
|
||||||
{
|
{
|
||||||
return dirname(__DIR__, 2) . '/';
|
return dirname(__DIR__, 2) . '/';
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ final class Froxlor
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function getVersion()
|
public static function getVersion(): string
|
||||||
{
|
{
|
||||||
return self::VERSION;
|
return self::VERSION;
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ final class Froxlor
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function getVersionString()
|
public static function getVersionString(): string
|
||||||
{
|
{
|
||||||
return self::getFullVersion() . ' (' . self::DBVERSION . ')';
|
return self::getFullVersion() . ' (' . self::DBVERSION . ')';
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ final class Froxlor
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function getFullVersion()
|
public static function getFullVersion(): string
|
||||||
{
|
{
|
||||||
return self::VERSION . self::BRANDING;
|
return self::VERSION . self::BRANDING;
|
||||||
}
|
}
|
||||||
@@ -85,12 +85,11 @@ final class Froxlor
|
|||||||
*
|
*
|
||||||
* checks if a given version is not equal the current one
|
* checks if a given version is not equal the current one
|
||||||
*
|
*
|
||||||
* @param string $to_check
|
* @param string $to_check version to check, if empty current version is used
|
||||||
* version to check, if empty current version is used
|
|
||||||
*
|
*
|
||||||
* @return bool true if version to check does not match, else false
|
* @return bool true if version to check does not match, else false
|
||||||
*/
|
*/
|
||||||
public static function hasUpdates($to_check = null)
|
public static function hasUpdates(string $to_check = ''): bool
|
||||||
{
|
{
|
||||||
if (empty($to_check)) {
|
if (empty($to_check)) {
|
||||||
$to_check = self::VERSION;
|
$to_check = self::VERSION;
|
||||||
@@ -102,16 +101,15 @@ final class Froxlor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function hasUpdates
|
* Function hasDbUpdates
|
||||||
*
|
*
|
||||||
* checks if a given database-version is not equal the current one
|
* checks if a given database-version is not equal the current one
|
||||||
*
|
*
|
||||||
* @param int $to_check
|
* @param string $to_check version to check, if empty current dbversion is used
|
||||||
* version to check, if empty current dbversion is used
|
|
||||||
*
|
*
|
||||||
* @return bool true if version to check does not match, else false
|
* @return bool true if version to check does not match, else false
|
||||||
*/
|
*/
|
||||||
public static function hasDbUpdates($to_check = null)
|
public static function hasDbUpdates(string $to_check = ''): bool
|
||||||
{
|
{
|
||||||
if (empty($to_check)) {
|
if (empty($to_check)) {
|
||||||
$to_check = self::DBVERSION;
|
$to_check = self::DBVERSION;
|
||||||
@@ -127,12 +125,11 @@ final class Froxlor
|
|||||||
*
|
*
|
||||||
* checks if a given database-version is the current one
|
* checks if a given database-version is the current one
|
||||||
*
|
*
|
||||||
* @param int $to_check
|
* @param string $to_check version to check
|
||||||
* version to check
|
|
||||||
*
|
*
|
||||||
* @return bool true if version to check matches, else false
|
* @return bool true if version to check matches, else false
|
||||||
*/
|
*/
|
||||||
public static function isDatabaseVersion($to_check = null)
|
public static function isDatabaseVersion(string $to_check): bool
|
||||||
{
|
{
|
||||||
if (Settings::Get('panel.frontend') == 'froxlor' && Settings::Get('panel.db_version') == $to_check) {
|
if (Settings::Get('panel.frontend') == 'froxlor' && Settings::Get('panel.db_version') == $to_check) {
|
||||||
return true;
|
return true;
|
||||||
@@ -146,14 +143,14 @@ final class Froxlor
|
|||||||
* updates the panel.version field
|
* updates the panel.version field
|
||||||
* to the given value (no checks here!)
|
* to the given value (no checks here!)
|
||||||
*
|
*
|
||||||
* @param string $new_version
|
* @param string $new_version new-version
|
||||||
* new-version
|
|
||||||
*
|
*
|
||||||
* @return bool true on success, else false
|
* @return bool true on success, else false
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function updateToDbVersion($new_version = null)
|
public static function updateToDbVersion(string $new_version): bool
|
||||||
{
|
{
|
||||||
if ($new_version !== null && $new_version != '') {
|
if ($new_version != '') {
|
||||||
$upd_stmt = Database::prepare("
|
$upd_stmt = Database::prepare("
|
||||||
UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = :newversion
|
UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = :newversion
|
||||||
WHERE `settinggroup` = 'panel' AND `varname` = 'db_version'");
|
WHERE `settinggroup` = 'panel' AND `varname` = 'db_version'");
|
||||||
@@ -172,14 +169,14 @@ final class Froxlor
|
|||||||
* updates the panel.version field
|
* updates the panel.version field
|
||||||
* to the given value (no checks here!)
|
* to the given value (no checks here!)
|
||||||
*
|
*
|
||||||
* @param string $new_version
|
* @param string $new_version new-version
|
||||||
* new-version
|
|
||||||
*
|
*
|
||||||
* @return bool true on success, else false
|
* @return bool true on success, else false
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function updateToVersion($new_version = null)
|
public static function updateToVersion(string $new_version): bool
|
||||||
{
|
{
|
||||||
if ($new_version !== null && $new_version != '') {
|
if ($new_version != '') {
|
||||||
$upd_stmt = Database::prepare("
|
$upd_stmt = Database::prepare("
|
||||||
UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = :newversion
|
UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = :newversion
|
||||||
WHERE `settinggroup` = 'panel' AND `varname` = 'version'");
|
WHERE `settinggroup` = 'panel' AND `varname` = 'version'");
|
||||||
@@ -199,7 +196,7 @@ final class Froxlor
|
|||||||
*
|
*
|
||||||
* @return bool true if panel is froxlor, else false
|
* @return bool true if panel is froxlor, else false
|
||||||
*/
|
*/
|
||||||
public static function isFroxlor()
|
public static function isFroxlor(): bool
|
||||||
{
|
{
|
||||||
if (Settings::Get('panel.frontend') !== null && Settings::Get('panel.frontend') == 'froxlor') {
|
if (Settings::Get('panel.frontend') !== null && Settings::Get('panel.frontend') == 'froxlor') {
|
||||||
return true;
|
return true;
|
||||||
@@ -213,12 +210,11 @@ final class Froxlor
|
|||||||
* checks if a given version is the
|
* checks if a given version is the
|
||||||
* current one (and panel is froxlor)
|
* current one (and panel is froxlor)
|
||||||
*
|
*
|
||||||
* @param string $to_check
|
* @param string $to_check version to check
|
||||||
* version to check
|
|
||||||
*
|
*
|
||||||
* @return bool true if version to check matches, else false
|
* @return bool true if version to check matches, else false
|
||||||
*/
|
*/
|
||||||
public static function isFroxlorVersion($to_check = null)
|
public static function isFroxlorVersion(string $to_check): bool
|
||||||
{
|
{
|
||||||
if (Settings::Get('panel.frontend') == 'froxlor' && Settings::Get('panel.version') == $to_check) {
|
if (Settings::Get('panel.frontend') == 'froxlor' && Settings::Get('panel.version') == $to_check) {
|
||||||
return true;
|
return true;
|
||||||
@@ -231,10 +227,11 @@ final class Froxlor
|
|||||||
*
|
*
|
||||||
* @param int $length
|
* @param int $length
|
||||||
* @return string
|
* @return string
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function genSessionId(int $length = 16)
|
public static function genSessionId(int $length = 16): string
|
||||||
{
|
{
|
||||||
if (intval($length) <= 8) {
|
if ($length <= 8) {
|
||||||
$length = 16;
|
$length = 16;
|
||||||
}
|
}
|
||||||
if (function_exists('random_bytes')) {
|
if (function_exists('random_bytes')) {
|
||||||
@@ -256,9 +253,9 @@ final class Froxlor
|
|||||||
* @param string $a
|
* @param string $a
|
||||||
* @param string $b
|
* @param string $b
|
||||||
*
|
*
|
||||||
* @return integer 0 if equal, 1 if a>b and -1 if b>a
|
* @return int 0 if equal, 1 if a>b and -1 if b>a
|
||||||
*/
|
*/
|
||||||
public static function versionCompare2($a, $b)
|
public static function versionCompare2(string $a, string $b): int
|
||||||
{
|
{
|
||||||
// split version into pieces and remove trailing .0
|
// split version into pieces and remove trailing .0
|
||||||
$a = explode(".", $a);
|
$a = explode(".", $a);
|
||||||
@@ -295,7 +292,11 @@ final class Froxlor
|
|||||||
return (count($a) < count($b)) ? -1 : 0;
|
return (count($a) < count($b)) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function parseVersionArray(&$arr = null)
|
/**
|
||||||
|
* @param array|null $arr
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function parseVersionArray(array &$arr = null)
|
||||||
{
|
{
|
||||||
// -dev or -beta or -rc ?
|
// -dev or -beta or -rc ?
|
||||||
if (stripos($arr[count($arr) - 1], '-') !== false) {
|
if (stripos($arr[count($arr) - 1], '-') !== false) {
|
||||||
@@ -306,12 +307,14 @@ final class Froxlor
|
|||||||
$arr[] = '2'; // dev < beta < rc
|
$arr[] = '2'; // dev < beta < rc
|
||||||
// number of rc
|
// number of rc
|
||||||
$arr[] = substr($x[1], 2);
|
$arr[] = substr($x[1], 2);
|
||||||
} else if (stripos($x[1], 'beta') !== false) {
|
} else {
|
||||||
|
if (stripos($x[1], 'beta') !== false) {
|
||||||
$arr[] = '-1';
|
$arr[] = '-1';
|
||||||
$arr[] = '1'; // dev < beta < rc
|
$arr[] = '1'; // dev < beta < rc
|
||||||
// number of beta
|
// number of beta
|
||||||
$arr[] = substr($x[1], 3);
|
$arr[] = substr($x[1], 3);
|
||||||
} else if (stripos($x[1], 'dev') !== false) {
|
} else {
|
||||||
|
if (stripos($x[1], 'dev') !== false) {
|
||||||
$arr[] = '-1';
|
$arr[] = '-1';
|
||||||
$arr[] = '0'; // dev < beta < rc
|
$arr[] = '0'; // dev < beta < rc
|
||||||
// number of dev
|
// number of dev
|
||||||
@@ -320,3 +323,5 @@ final class Froxlor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,38 +45,42 @@ class FroxlorLogger
|
|||||||
/**
|
/**
|
||||||
* current \Monolog\Logger object
|
* current \Monolog\Logger object
|
||||||
*
|
*
|
||||||
* @var Logger
|
* @var ?Logger
|
||||||
*/
|
*/
|
||||||
private static $ml = null;
|
private static ?Logger $ml = null;
|
||||||
/**
|
/**
|
||||||
* LogTypes Array
|
* LogTypes Array
|
||||||
*
|
*
|
||||||
* @var array
|
* @var ?array
|
||||||
*/
|
*/
|
||||||
private static $logtypes = null;
|
private static ?array $logtypes = null;
|
||||||
/**
|
/**
|
||||||
* whether to output log-messages to STDOUT (cron)
|
* whether to output log-messages to STDOUT (cron)
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private static $crondebug_flag = false;
|
private static bool $crondebug_flag = false;
|
||||||
/**
|
/**
|
||||||
* user info of logged in user
|
* user info of logged-in user
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private static $userinfo = [];
|
private static array $userinfo = [];
|
||||||
/**
|
/**
|
||||||
* whether the logger object has already been initialized
|
* whether the logger object has already been initialized
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private static $is_initialized = false;
|
private static bool $is_initialized = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor.
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param array $userinfo
|
||||||
|
*
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function __construct($userinfo = [])
|
protected function __construct(array $userinfo = [])
|
||||||
{
|
{
|
||||||
$this->initMonolog();
|
$this->initMonolog();
|
||||||
self::$userinfo = $userinfo;
|
self::$userinfo = $userinfo;
|
||||||
@@ -100,11 +104,17 @@ class FroxlorLogger
|
|||||||
self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG));
|
self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG));
|
||||||
break;
|
break;
|
||||||
case 'file':
|
case 'file':
|
||||||
$logger_logfile = Settings::Get('logger.logfile');
|
$logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/' . Settings::Get('logger.logfile'));
|
||||||
// is_writable needs an existing file to check if it's actually writable
|
// is_writable needs an existing file to check if it's actually writable
|
||||||
@touch($logger_logfile);
|
@touch($logger_logfile);
|
||||||
if (empty($logger_logfile) || !is_writable($logger_logfile)) {
|
if (empty($logger_logfile) || !is_writable($logger_logfile)) {
|
||||||
Settings::Set('logger.logfile', '/tmp/froxlor.log');
|
Settings::Set('logger.logfile', 'froxlor.log');
|
||||||
|
$logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/froxlor.log');
|
||||||
|
@touch($logger_logfile);
|
||||||
|
if (empty($logger_logfile) || !is_writable($logger_logfile)) {
|
||||||
|
// not writable in our own directory? Skip
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self::$ml->pushHandler(new StreamHandler($logger_logfile, Logger::DEBUG));
|
self::$ml->pushHandler(new StreamHandler($logger_logfile, Logger::DEBUG));
|
||||||
break;
|
break;
|
||||||
@@ -137,8 +147,9 @@ class FroxlorLogger
|
|||||||
* @param array $userinfo
|
* @param array $userinfo
|
||||||
*
|
*
|
||||||
* @return FroxlorLogger
|
* @return FroxlorLogger
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function getInstanceOf($userinfo = [])
|
public static function getInstanceOf(array $userinfo = [])
|
||||||
{
|
{
|
||||||
if (empty($userinfo)) {
|
if (empty($userinfo)) {
|
||||||
$userinfo = [
|
$userinfo = [
|
||||||
@@ -153,9 +164,9 @@ class FroxlorLogger
|
|||||||
*
|
*
|
||||||
* @param int $action
|
* @param int $action
|
||||||
* @param int $type
|
* @param int $type
|
||||||
* @param string $text
|
* @param ?string $text
|
||||||
*/
|
*/
|
||||||
public function logAction($action = FroxlorLogger::USR_ACTION, $type = LOG_NOTICE, $text = null)
|
public function logAction($action = FroxlorLogger::USR_ACTION, int $type = LOG_NOTICE, string $text = null)
|
||||||
{
|
{
|
||||||
// not logging normal stuff if not set to "paranoid" logging
|
// not logging normal stuff if not set to "paranoid" logging
|
||||||
if (!self::$crondebug_flag && Settings::Get('logger.severity') == '1' && $type > LOG_NOTICE) {
|
if (!self::$crondebug_flag && Settings::Get('logger.severity') == '1' && $type > LOG_NOTICE) {
|
||||||
@@ -202,7 +213,11 @@ class FroxlorLogger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLogLevelDesc($type)
|
/**
|
||||||
|
* @param int $type
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLogLevelDesc(int $type): string
|
||||||
{
|
{
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case LOG_INFO:
|
case LOG_INFO:
|
||||||
@@ -230,7 +245,11 @@ class FroxlorLogger
|
|||||||
return $_type;
|
return $_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getActionTypeDesc($action)
|
/**
|
||||||
|
* @param $action
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getActionTypeDesc($action): string
|
||||||
{
|
{
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case FroxlorLogger::USR_ACTION:
|
case FroxlorLogger::USR_ACTION:
|
||||||
@@ -262,7 +281,7 @@ class FroxlorLogger
|
|||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function setCronLog(int $cronlog = 0)
|
public function setCronLog(int $cronlog = 0): int
|
||||||
{
|
{
|
||||||
if ($cronlog < 0 || $cronlog > 2) {
|
if ($cronlog < 0 || $cronlog > 2) {
|
||||||
$cronlog = 0;
|
$cronlog = 0;
|
||||||
|
|||||||
@@ -47,15 +47,17 @@ class Directory
|
|||||||
*
|
*
|
||||||
* @param string $dir
|
* @param string $dir
|
||||||
*/
|
*/
|
||||||
public function __construct($dir = null)
|
public function __construct(string $dir = null)
|
||||||
{
|
{
|
||||||
$this->dir = $dir;
|
$this->dir = $dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check whether the directory has options set in panel_htaccess
|
* check whether the directory has options set in panel_htaccess
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function hasUserOptions()
|
public function hasUserOptions(): bool
|
||||||
{
|
{
|
||||||
$uo_stmt = Database::prepare("
|
$uo_stmt = Database::prepare("
|
||||||
SELECT COUNT(`id`) as `usropts` FROM `" . TABLE_PANEL_HTACCESS . "` WHERE `path` = :dir
|
SELECT COUNT(`id`) as `usropts` FROM `" . TABLE_PANEL_HTACCESS . "` WHERE `path` = :dir
|
||||||
@@ -63,7 +65,7 @@ class Directory
|
|||||||
$uo_res = Database::pexecute_first($uo_stmt, [
|
$uo_res = Database::pexecute_first($uo_stmt, [
|
||||||
'dir' => FileDir::makeCorrectDir($this->dir)
|
'dir' => FileDir::makeCorrectDir($this->dir)
|
||||||
]);
|
]);
|
||||||
if ($uo_res != false && isset($uo_res['usropts'])) {
|
if ($uo_res && isset($uo_res['usropts'])) {
|
||||||
return $uo_res['usropts'] > 0;
|
return $uo_res['usropts'] > 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -71,8 +73,10 @@ class Directory
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* check whether the directory is protected using panel_htpasswd
|
* check whether the directory is protected using panel_htpasswd
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isUserProtected()
|
public function isUserProtected(): bool
|
||||||
{
|
{
|
||||||
$up_stmt = Database::prepare("
|
$up_stmt = Database::prepare("
|
||||||
SELECT COUNT(`id`) as `usrprot` FROM `" . TABLE_PANEL_HTPASSWDS . "` WHERE `path` = :dir
|
SELECT COUNT(`id`) as `usrprot` FROM `" . TABLE_PANEL_HTPASSWDS . "` WHERE `path` = :dir
|
||||||
@@ -80,7 +84,7 @@ class Directory
|
|||||||
$up_res = Database::pexecute_first($up_stmt, [
|
$up_res = Database::pexecute_first($up_stmt, [
|
||||||
'dir' => FileDir::makeCorrectDir($this->dir)
|
'dir' => FileDir::makeCorrectDir($this->dir)
|
||||||
]);
|
]);
|
||||||
if ($up_res != false && isset($up_res['usrprot'])) {
|
if ($up_res && isset($up_res['usrprot'])) {
|
||||||
return $up_res['usrprot'] > 0;
|
return $up_res['usrprot'] > 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -90,12 +94,11 @@ class Directory
|
|||||||
* Checks if a given directory is valid for multiple configurations
|
* Checks if a given directory is valid for multiple configurations
|
||||||
* or should rather be used as a single file
|
* or should rather be used as a single file
|
||||||
*
|
*
|
||||||
* @param bool $ifexists
|
* @param bool $ifexists also check whether file/dir exists
|
||||||
* also check whether file/dir exists
|
|
||||||
*
|
*
|
||||||
* @return bool true if usable as dir, false otherwise
|
* @return bool true if usable as dir, false otherwise
|
||||||
*/
|
*/
|
||||||
public function isConfigDir($ifexists = false)
|
public function isConfigDir(bool $ifexists = false): bool
|
||||||
{
|
{
|
||||||
if (is_null($this->dir)) {
|
if (is_null($this->dir)) {
|
||||||
trigger_error(__CLASS__ . '::' . __FUNCTION__ . ' has been called with a null value', E_USER_WARNING);
|
trigger_error(__CLASS__ . '::' . __FUNCTION__ . ' has been called with a null value', E_USER_WARNING);
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ class HttpClient
|
|||||||
/**
|
/**
|
||||||
* Executes simple GET request
|
* Executes simple GET request
|
||||||
*
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param bool $follow_location
|
||||||
|
* @param int $timeout
|
||||||
|
*
|
||||||
* @return bool|string
|
* @return bool|string
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@@ -59,6 +63,10 @@ class HttpClient
|
|||||||
/**
|
/**
|
||||||
* Downloads and stores a file from an url
|
* Downloads and stores a file from an url
|
||||||
*
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param string $target
|
||||||
|
*
|
||||||
|
* @return bool|string
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function fileGet(string $url, string $target)
|
public static function fileGet(string $url, string $target)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class PhpConfig
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function getPhpConfigs()
|
public static function getPhpConfigs(): array
|
||||||
{
|
{
|
||||||
$configs_array = [];
|
$configs_array = [];
|
||||||
|
|
||||||
|
|||||||
55
lib/Froxlor/Http/RateLimiter.php
Normal file
55
lib/Froxlor/Http/RateLimiter.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Http;
|
||||||
|
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
use Froxlor\UI\Panel\UI;
|
||||||
|
|
||||||
|
class RateLimiter
|
||||||
|
{
|
||||||
|
private static int $limit_per_interval = 60;
|
||||||
|
private static int $reset_time = 0;
|
||||||
|
|
||||||
|
public static function run(bool $install_mode = false)
|
||||||
|
{
|
||||||
|
// default interval = 60 sec
|
||||||
|
self::$reset_time = time() + 60;
|
||||||
|
|
||||||
|
if (!$install_mode) {
|
||||||
|
self::$limit_per_interval = Settings::Get('system.req_limit_per_interval');
|
||||||
|
self::$reset_time = time() + Settings::Get('system.req_limit_interval');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the remaining requests and reset time from the headers
|
||||||
|
$remaining = isset($_SESSION['HTTP_X_RATELIMIT_REMAINING']) ? (int)$_SESSION['HTTP_X_RATELIMIT_REMAINING'] : self::$limit_per_interval;
|
||||||
|
$reset = isset($_SESSION['HTTP_X_RATELIMIT_RESET']) ? (int)$_SESSION['HTTP_X_RATELIMIT_RESET'] : self::$reset_time;
|
||||||
|
|
||||||
|
// check if reset time is due
|
||||||
|
if (time() > $reset) {
|
||||||
|
$remaining = self::$limit_per_interval;
|
||||||
|
$reset = self::$reset_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've hit the limit, return an error
|
||||||
|
if ($remaining <= 0) {
|
||||||
|
header('HTTP/1.1 429 Too Many Requests');
|
||||||
|
header("Retry-After: $reset");
|
||||||
|
UI::twig()->addGlobal('install_mode', '1');
|
||||||
|
echo UI::twig()->render('Froxlor/misc/ratelimithint.html.twig', [
|
||||||
|
'retry' => $reset,
|
||||||
|
'installdir' => Froxlor::getInstallDir()
|
||||||
|
]);
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrement the remaining requests and update the headers
|
||||||
|
$remaining--;
|
||||||
|
$_SESSION['HTTP_X_RATELIMIT_REMAINING'] = $remaining;
|
||||||
|
$_SESSION['HTTP_X_RATELIMIT_RESET'] = $reset;
|
||||||
|
|
||||||
|
header("X-RateLimit-Limit: " . self::$limit_per_interval);
|
||||||
|
header("X-RateLimit-Remaining: " . $remaining);
|
||||||
|
header("X-RateLimit-Reset: " . $reset);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,16 +36,22 @@ class Statistics
|
|||||||
* Create or modify the AWStats configuration file for the given domain.
|
* Create or modify the AWStats configuration file for the given domain.
|
||||||
* Modified by Berend Dekens to allow custom configurations.
|
* Modified by Berend Dekens to allow custom configurations.
|
||||||
*
|
*
|
||||||
* @param
|
* @param string $logFile
|
||||||
* logFile
|
* @param string $siteDomain
|
||||||
* @param
|
* @param string $hostAliases
|
||||||
* siteDomain
|
* @param string $customerDocroot
|
||||||
* @param
|
* @param array $domain_data
|
||||||
* hostAliases
|
*
|
||||||
* @return null
|
* @return null
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function createAWStatsConf($logFile, $siteDomain, $hostAliases, $customerDocroot, $awstats_params = [])
|
public static function createAWStatsConf(
|
||||||
{
|
string $logFile,
|
||||||
|
string $siteDomain,
|
||||||
|
string $hostAliases,
|
||||||
|
string $customerDocroot,
|
||||||
|
array $domain_data = []
|
||||||
|
) {
|
||||||
// Generation header
|
// Generation header
|
||||||
$header = "## GENERATED BY FROXLOR\n";
|
$header = "## GENERATED BY FROXLOR\n";
|
||||||
$header2 = "## Do not remove the line above! This tells Froxlor to update this configuration\n## If you wish to manually change this configuration file, remove the first line to make sure Froxlor won't rebuild this file\n## Generated for domain {SITE_DOMAIN} on " . date('l dS \of F Y h:i:s A') . "\n";
|
$header2 = "## Do not remove the line above! This tells Froxlor to update this configuration\n## If you wish to manually change this configuration file, remove the first line to make sure Froxlor won't rebuild this file\n## Generated for domain {SITE_DOMAIN} on " . date('l dS \of F Y h:i:s A') . "\n";
|
||||||
@@ -55,7 +61,7 @@ class Statistics
|
|||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg($awstats_dir));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($awstats_dir));
|
||||||
}
|
}
|
||||||
// chown created folder, #258
|
// chown created folder, #258
|
||||||
self::makeChownWithNewStats($awstats_params);
|
self::makeChownWithNewStats($domain_data);
|
||||||
|
|
||||||
// weird but could happen...
|
// weird but could happen...
|
||||||
if (!is_dir(Settings::Get('system.awstats_conf'))) {
|
if (!is_dir(Settings::Get('system.awstats_conf'))) {
|
||||||
@@ -127,16 +133,15 @@ class Statistics
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* chowns either awstats or webalizer folder,
|
* chowns stats-tools folder, either with webserver-user or
|
||||||
* either with webserver-user or - if fcgid
|
* if fcgid/php-fpm is used, the customers name, #258
|
||||||
* is used - the customers name, #258
|
|
||||||
*
|
*
|
||||||
* @param array $row
|
* @param array $row array of panel_customers
|
||||||
* array if panel_customers
|
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function makeChownWithNewStats($row)
|
public static function makeChownWithNewStats(array $row)
|
||||||
{
|
{
|
||||||
// get correct user
|
// get correct user
|
||||||
if ((Settings::Get('system.mod_fcgid') == '1' || Settings::Get('phpfpm.enabled') == '1') && isset($row['deactivated']) && $row['deactivated'] == '0') {
|
if ((Settings::Get('system.mod_fcgid') == '1' || Settings::Get('phpfpm.enabled') == '1') && isset($row['deactivated']) && $row['deactivated'] == '0') {
|
||||||
|
|||||||
@@ -54,16 +54,15 @@ class IdnaWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode a domain name, a email address or a list of one of both.
|
* Encode a domain name, an email address or a list of one of both.
|
||||||
*
|
*
|
||||||
* @param
|
* @param string $to_encode May be either a single domain name, e single email address or a list of one
|
||||||
* string May be either a single domain name, e single email address or a list of one
|
|
||||||
* separated either by ',', ';' or ' '.
|
* separated either by ',', ';' or ' '.
|
||||||
*
|
*
|
||||||
* @return string Returns either a single domain name, a single email address or a list of one of
|
* @return string Returns either a single domain name, a single email address or a list of one of
|
||||||
* both separated by the same string as the input.
|
* both separated by the same string as the input.
|
||||||
*/
|
*/
|
||||||
public function encode($to_encode)
|
public function encode(string $to_encode): string
|
||||||
{
|
{
|
||||||
$to_encode = $this->isUtf8($to_encode) ? $to_encode : utf8_encode($to_encode);
|
$to_encode = $this->isUtf8($to_encode) ? $to_encode : utf8_encode($to_encode);
|
||||||
try {
|
try {
|
||||||
@@ -83,7 +82,7 @@ class IdnaWrapper
|
|||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
private function isUtf8($string = null)
|
private function isUtf8(string $string)
|
||||||
{
|
{
|
||||||
if (function_exists("mb_detect_encoding")) {
|
if (function_exists("mb_detect_encoding")) {
|
||||||
if (mb_detect_encoding($string, 'UTF-8, ISO-8859-1') === 'UTF-8') {
|
if (mb_detect_encoding($string, 'UTF-8, ISO-8859-1') === 'UTF-8') {
|
||||||
@@ -119,16 +118,15 @@ class IdnaWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a domain name, a email address or a list of one of both.
|
* Decode a domain name, an email address or a list of one of both.
|
||||||
*
|
*
|
||||||
* @param
|
* @param string $to_decode May be either a single domain name, e single email address or a list of one
|
||||||
* string May be either a single domain name, e single email address or a list of one
|
|
||||||
* separated either by ',', ';' or ' '.
|
* separated either by ',', ';' or ' '.
|
||||||
*
|
*
|
||||||
* @return string Returns either a single domain name, a single email address or a list of one of
|
* @return string Returns either a single domain name, a single email address or a list of one of
|
||||||
* both separated by the same string as the input.
|
* both separated by the same string as the input.
|
||||||
*/
|
*/
|
||||||
public function decode($to_decode)
|
public function decode(string $to_decode): string
|
||||||
{
|
{
|
||||||
return $this->idna_converter->decode($to_decode);
|
return $this->idna_converter->decode($to_decode);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class Install
|
|||||||
public $phpVersion;
|
public $phpVersion;
|
||||||
public $formfield;
|
public $formfield;
|
||||||
public string $requiredVersion = '7.4.0';
|
public string $requiredVersion = '7.4.0';
|
||||||
public array $requiredExtensions = ['session', 'ctype', 'xml', 'filter', 'posix', 'mbstring', 'curl', 'gmp', 'json'];
|
public array $requiredExtensions = ['session', 'ctype', 'mysql', 'xml', 'filter', 'posix', 'mbstring', 'curl', 'gmp', 'json', 'gd'];
|
||||||
public array $suggestedExtensions = ['bcmath', 'zip'];
|
public array $suggestedExtensions = ['bcmath', 'zip'];
|
||||||
public array $suggestions = [];
|
public array $suggestions = [];
|
||||||
public array $criticals = [];
|
public array $criticals = [];
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ class Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->updateSetting($upd_stmt, $this->validatedData['activate_newsfeed'], 'admin', 'show_news_feed');
|
$this->updateSetting($upd_stmt, $this->validatedData['activate_newsfeed'], 'admin', 'show_news_feed');
|
||||||
$this->updateSetting($upd_stmt, dirname(__FILE__, 3), 'system', 'letsencryptchallengepath');
|
$this->updateSetting($upd_stmt, dirname(__FILE__, 5), 'system', 'letsencryptchallengepath');
|
||||||
|
|
||||||
// insert the lastcronrun to be the installation date
|
// insert the lastcronrun to be the installation date
|
||||||
$this->updateSetting($upd_stmt, time(), 'system', 'lastcronrun');
|
$this->updateSetting($upd_stmt, time(), 'system', 'lastcronrun');
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class Preconfig
|
|||||||
$agree = [
|
$agree = [
|
||||||
'title' => 'Check',
|
'title' => 'Check',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'update_changesagreed' => ['type' => 'checkbox', 'value' => 1, 'label' => '<strong>I have read the update notifications above and I am aware of the changes made to my system.</strong>'],
|
'update_changesagreed' => ['mandatory' => true, 'type' => 'checkrequired', 'value' => 1, 'label' => '<strong>I have read the update notifications above and I am aware of the changes made to my system.</strong>'],
|
||||||
'update_preconfig' => ['type' => 'hidden', 'value' => 1]
|
'update_preconfig' => ['type' => 'hidden', 'value' => 1]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -68,10 +68,10 @@ class MailLogParser
|
|||||||
// Parse MDA traffic
|
// Parse MDA traffic
|
||||||
if (Settings::Get("system.mdaserver") == "dovecot") {
|
if (Settings::Get("system.mdaserver") == "dovecot") {
|
||||||
$this->parseDovecotLog(Settings::Get("system.mdalog"));
|
$this->parseDovecotLog(Settings::Get("system.mdalog"));
|
||||||
$this->parsePostfixLog(Settings::Get("system.mdalog") . ".1");
|
$this->parseDovecotLog(Settings::Get("system.mdalog") . ".1");
|
||||||
} elseif (Settings::Get("system.mdaserver") == "courier") {
|
} elseif (Settings::Get("system.mdaserver") == "courier") {
|
||||||
$this->parseCourierLog(Settings::Get("system.mdalog"));
|
$this->parseCourierLog(Settings::Get("system.mdalog"));
|
||||||
$this->parsePostfixLog(Settings::Get("system.mdalog") . ".1");
|
$this->parseCourierLog(Settings::Get("system.mdalog") . ".1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ namespace Froxlor;
|
|||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
|
use Net_DNS2_Exception;
|
||||||
|
use Net_DNS2_Resolver;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use voku\helper\AntiXSS;
|
use voku\helper\AntiXSS;
|
||||||
|
|
||||||
@@ -41,9 +43,9 @@ class PhpHelper
|
|||||||
* @param array $list
|
* @param array $list
|
||||||
* @param string $key
|
* @param string $key
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function sortListBy(&$list, $key = 'id')
|
public static function sortListBy(array &$list, string $key = 'id'): bool
|
||||||
{
|
{
|
||||||
self::$sort_type = Settings::Get('panel.natsorting') == 1 ? SORT_NATURAL : SORT_STRING;
|
self::$sort_type = Settings::Get('panel.natsorting') == 1 ? SORT_NATURAL : SORT_STRING;
|
||||||
self::$sort_key = $key;
|
self::$sort_key = $key;
|
||||||
@@ -57,14 +59,10 @@ class PhpHelper
|
|||||||
* Wrapper around htmlentities to handle arrays, with the advantage that you
|
* Wrapper around htmlentities to handle arrays, with the advantage that you
|
||||||
* can select which fields should be handled by htmlentities
|
* can select which fields should be handled by htmlentities
|
||||||
*
|
*
|
||||||
* @param array|string $subject
|
* @param array|string $subject The subject array
|
||||||
* The subject array
|
* @param array|string $fields The fields which should be checked for, separated by spaces
|
||||||
* @param string $fields
|
* @param int $quote_style See php documentation about this
|
||||||
* The fields which should be checked for, separated by spaces
|
* @param string $charset See php documentation about this
|
||||||
* @param int $quote_style
|
|
||||||
* See php documentation about this
|
|
||||||
* @param string $charset
|
|
||||||
* See php documentation about this
|
|
||||||
*
|
*
|
||||||
* @return array|string The string or an array with htmlentities converted strings
|
* @return array|string The string or an array with htmlentities converted strings
|
||||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
||||||
@@ -77,7 +75,7 @@ class PhpHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($subject as $field => $value) {
|
foreach ($subject as $field => $value) {
|
||||||
if ((!is_array($fields) || empty($fields)) || (is_array($fields) && !empty($fields) && in_array($field, $fields))) {
|
if ((!is_array($fields) || empty($fields)) || (in_array($field, $fields))) {
|
||||||
// Just call ourselve to manage multi-dimensional arrays
|
// Just call ourselve to manage multi-dimensional arrays
|
||||||
$subject[$field] = self::htmlentitiesArray($value, $fields, $quote_style, $charset);
|
$subject[$field] = self::htmlentitiesArray($value, $fields, $quote_style, $charset);
|
||||||
}
|
}
|
||||||
@@ -92,45 +90,36 @@ class PhpHelper
|
|||||||
/**
|
/**
|
||||||
* Returns array with all empty-values removed
|
* Returns array with all empty-values removed
|
||||||
*
|
*
|
||||||
* @param array $source
|
* @param array $source The array to trim
|
||||||
* The array to trim
|
|
||||||
* @return array The trim'med array
|
* @return array The trim'med array
|
||||||
*/
|
*/
|
||||||
public static function arrayTrim($source)
|
public static function arrayTrim(array $source): array
|
||||||
{
|
{
|
||||||
$returnval = [];
|
|
||||||
if (is_array($source)) {
|
|
||||||
$source = array_map('trim', $source);
|
$source = array_map('trim', $source);
|
||||||
$returnval = array_filter($source, function ($value) {
|
return array_filter($source, function ($value) {
|
||||||
return $value !== '';
|
return $value !== '';
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
$returnval = $source;
|
|
||||||
}
|
|
||||||
return $returnval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces Strings in an array, with the advantage that you
|
* Replaces Strings in an array, with the advantage that you
|
||||||
* can select which fields should be str_replace'd
|
* can select which fields should be str_replace'd
|
||||||
*
|
*
|
||||||
* @param string|array $search
|
* @param string|array $search String or array of strings to search for
|
||||||
* String or array of strings to search for
|
* @param string|array $replace String or array to replace with
|
||||||
* @param string|array $reaplce
|
* @param string|array $subject String or array The subject array
|
||||||
* String or array to replace with
|
* @param string|array $fields string The fields which should be checked for, separated by spaces
|
||||||
* @param string|array $subject
|
*
|
||||||
* String or array The subject array
|
|
||||||
* @param string $fields
|
|
||||||
* string The fields which should be checked for, separated by spaces
|
|
||||||
* @return string|array The str_replace'd array
|
* @return string|array The str_replace'd array
|
||||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
|
||||||
*/
|
*/
|
||||||
public static function strReplaceArray($search, $replace, $subject, $fields = '')
|
public static function strReplaceArray($search, $replace, $subject, $fields = '')
|
||||||
{
|
{
|
||||||
if (is_array($subject)) {
|
if (is_array($subject)) {
|
||||||
|
if (!is_array($fields)) {
|
||||||
$fields = self::arrayTrim(explode(' ', $fields));
|
$fields = self::arrayTrim(explode(' ', $fields));
|
||||||
|
}
|
||||||
foreach ($subject as $field => $value) {
|
foreach ($subject as $field => $value) {
|
||||||
if ((!is_array($fields) || empty($fields)) || (is_array($fields) && !empty($fields) && in_array($field, $fields))) {
|
if ((!is_array($fields) || empty($fields)) || (in_array($field, $fields))) {
|
||||||
$subject[$field] = str_replace($search, $replace, $value);
|
$subject[$field] = str_replace($search, $replace, $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +164,8 @@ class PhpHelper
|
|||||||
$err_display .= '<br><p><pre>';
|
$err_display .= '<br><p><pre>';
|
||||||
$debug = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
$debug = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||||
foreach ($debug as $dline) {
|
foreach ($debug as $dline) {
|
||||||
$err_display .= $dline['function'] . '() called at [' . str_replace(Froxlor::getInstallDir(), '', ($dline['file'] ?? 'unknown')) . ':' . ($dline['line'] ?? 0) . ']<br>';
|
$err_display .= $dline['function'] . '() called at [' . str_replace(Froxlor::getInstallDir(), '',
|
||||||
|
($dline['file'] ?? 'unknown')) . ':' . ($dline['line'] ?? 0) . ']<br>';
|
||||||
}
|
}
|
||||||
$err_display .= '</pre></p>';
|
$err_display .= '</pre></p>';
|
||||||
// end later
|
// end later
|
||||||
@@ -191,9 +181,13 @@ class PhpHelper
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Throwable $exception
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public static function phpExceptionHandler(Throwable $exception)
|
public static function phpExceptionHandler(Throwable $exception)
|
||||||
{
|
{
|
||||||
if (!isset($_SERVER['SHELL']) || (isset($_SERVER['SHELL']) && $_SERVER['SHELL'] == '')) {
|
if (!isset($_SERVER['SHELL']) || $_SERVER['SHELL'] == '') {
|
||||||
// show
|
// show
|
||||||
UI::initTwig(true);
|
UI::initTwig(true);
|
||||||
UI::twig()->addGlobal('install_mode', '1');
|
UI::twig()->addGlobal('install_mode', '1');
|
||||||
@@ -208,6 +202,10 @@ class PhpHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ...$configdirs
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
public static function loadConfigArrayDir(...$configdirs)
|
public static function loadConfigArrayDir(...$configdirs)
|
||||||
{
|
{
|
||||||
if (count($configdirs) <= 0) {
|
if (count($configdirs) <= 0) {
|
||||||
@@ -222,7 +220,8 @@ class PhpHelper
|
|||||||
if (is_dir($data_dirname)) {
|
if (is_dir($data_dirname)) {
|
||||||
$data_dirhandle = opendir($data_dirname);
|
$data_dirhandle = opendir($data_dirname);
|
||||||
while (false !== ($data_filename = readdir($data_dirhandle))) {
|
while (false !== ($data_filename = readdir($data_dirhandle))) {
|
||||||
if ($data_filename != '.' && $data_filename != '..' && $data_filename != '' && substr($data_filename, -4) == '.php') {
|
if ($data_filename != '.' && $data_filename != '..' && $data_filename != '' && substr($data_filename,
|
||||||
|
-4) == '.php') {
|
||||||
$data_files[] = $data_dirname . $data_filename;
|
$data_files[] = $data_dirname . $data_filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,47 +243,66 @@ class PhpHelper
|
|||||||
* ipv6 aware gethostbynamel function
|
* ipv6 aware gethostbynamel function
|
||||||
*
|
*
|
||||||
* @param string $host
|
* @param string $host
|
||||||
* @param boolean $try_a
|
* @param boolean $try_a default true
|
||||||
* default true
|
* @param string|null $nameserver set additional resolver nameserver to use (e.g. 1.1.1.1)
|
||||||
* @return boolean|array
|
* @return bool|array
|
||||||
*/
|
*/
|
||||||
public static function gethostbynamel6($host, $try_a = true)
|
public static function gethostbynamel6(string $host, bool $try_a = true, string $nameserver = null)
|
||||||
{
|
{
|
||||||
$dns6 = @dns_get_record($host, DNS_AAAA);
|
|
||||||
if (!is_array($dns6)) {
|
|
||||||
// no record or failed to check
|
|
||||||
$dns6 = [];
|
|
||||||
}
|
|
||||||
if ($try_a == true) {
|
|
||||||
$dns4 = @dns_get_record($host, DNS_A);
|
|
||||||
if (!is_array($dns4)) {
|
|
||||||
// no record or failed to check
|
|
||||||
$dns4 = [];
|
|
||||||
}
|
|
||||||
$dns = array_merge($dns4, $dns6);
|
|
||||||
} else {
|
|
||||||
$dns = $dns6;
|
|
||||||
}
|
|
||||||
$ips = [];
|
$ips = [];
|
||||||
foreach ($dns as $record) {
|
|
||||||
if ($record["type"] == "A") {
|
try {
|
||||||
// always use compressed ipv6 format
|
// set the default nameservers to use, use the system default if none are provided
|
||||||
$ip = inet_ntop(inet_pton($record["ip"]));
|
$resolver = new Net_DNS2_Resolver($nameserver ? ['nameservers' => [$nameserver]] : []);
|
||||||
$ips[] = $ip;
|
|
||||||
}
|
// get all ip addresses from the A record and normalize them
|
||||||
if ($record["type"] == "AAAA") {
|
if ($try_a) {
|
||||||
// always use compressed ipv6 format
|
try {
|
||||||
$ip = inet_ntop(inet_pton($record["ipv6"]));
|
$answer = $resolver->query($host, 'A')->answer;
|
||||||
$ips[] = $ip;
|
foreach ($answer as $rr) {
|
||||||
|
if ($rr instanceof \Net_DNS2_RR_A) {
|
||||||
|
$ips[] = inet_ntop(inet_pton($rr->address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count($ips) < 1) {
|
} catch (Net_DNS2_Exception $e) {
|
||||||
return false;
|
// we can't do anything here, just continue
|
||||||
} else {
|
|
||||||
return $ips;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get all ip addresses from the AAAA record and normalize them
|
||||||
|
try {
|
||||||
|
$answer = $resolver->query($host, 'AAAA')->answer;
|
||||||
|
foreach ($answer as $rr) {
|
||||||
|
if ($rr instanceof \Net_DNS2_RR_AAAA) {
|
||||||
|
$ips[] = inet_ntop(inet_pton($rr->address));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Net_DNS2_Exception $e) {
|
||||||
|
// we can't do anything here, just continue
|
||||||
|
}
|
||||||
|
} catch (Net_DNS2_Exception $e) {
|
||||||
|
// fallback to php's dns_get_record if Net_DNS2 has no resolver available, but this may cause
|
||||||
|
// problems if the system's dns is not configured correctly; for example, the acme pre-check
|
||||||
|
// will fail because some providers put a local ip in /etc/hosts
|
||||||
|
|
||||||
|
// get all ip addresses from the A record and normalize them
|
||||||
|
if ($try_a) {
|
||||||
|
$answer = @dns_get_record($host, DNS_A);
|
||||||
|
foreach ($answer as $rr) {
|
||||||
|
$ips[] = inet_ntop(inet_pton($rr['ip']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all ip addresses from the AAAA record and normalize them
|
||||||
|
$answer = @dns_get_record($host, DNS_AAAA);
|
||||||
|
foreach ($answer as $rr) {
|
||||||
|
$ips[] = inet_ntop(inet_pton($rr['ipv6']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count($ips) > 0 ? $ips : false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function randomStr
|
* Function randomStr
|
||||||
*
|
*
|
||||||
@@ -294,7 +312,7 @@ class PhpHelper
|
|||||||
* @return string
|
* @return string
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function randomStr($length)
|
public static function randomStr(int $length): string
|
||||||
{
|
{
|
||||||
if (function_exists('openssl_random_pseudo_bytes')) {
|
if (function_exists('openssl_random_pseudo_bytes')) {
|
||||||
return openssl_random_pseudo_bytes($length);
|
return openssl_random_pseudo_bytes($length);
|
||||||
@@ -303,20 +321,21 @@ class PhpHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return human readable sizes
|
* Return human-readable sizes
|
||||||
*
|
*
|
||||||
* @param int $size
|
* @param int $size size in bytes
|
||||||
* size in bytes
|
* @param ?string $max maximum unit
|
||||||
* @param string $max
|
* @param string $system 'si' for SI, 'bi' for binary prefixes
|
||||||
* maximum unit
|
* @param string $retstring string-format
|
||||||
* @param string $system
|
|
||||||
* 'si' for SI, 'bi' for binary prefixes
|
|
||||||
*
|
*
|
||||||
* @param string $retstring
|
* @return string
|
||||||
* string
|
|
||||||
*/
|
*/
|
||||||
public static function sizeReadable($size, $max = null, $system = 'si', $retstring = '%01.2f %s')
|
public static function sizeReadable(
|
||||||
{
|
$size,
|
||||||
|
?string $max = '',
|
||||||
|
string $system = 'si',
|
||||||
|
string $retstring = '%01.2f %s'
|
||||||
|
): string {
|
||||||
// Pick units
|
// Pick units
|
||||||
$systems = [
|
$systems = [
|
||||||
'si' => [
|
'si' => [
|
||||||
@@ -342,7 +361,7 @@ class PhpHelper
|
|||||||
'size' => 1024
|
'size' => 1024
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
$sys = isset($systems[$system]) ? $systems[$system] : $systems['si'];
|
$sys = $systems[$system] ?? $systems['si'];
|
||||||
|
|
||||||
// Max unit to display
|
// Max unit to display
|
||||||
$depth = count($sys['prefix']) - 1;
|
$depth = count($sys['prefix']) - 1;
|
||||||
@@ -363,14 +382,12 @@ class PhpHelper
|
|||||||
* Replaces all occurrences of variables defined in the second argument
|
* Replaces all occurrences of variables defined in the second argument
|
||||||
* in the first argument with their values.
|
* in the first argument with their values.
|
||||||
*
|
*
|
||||||
* @param string $text
|
* @param string $text The string that should be searched for variables
|
||||||
* The string that should be searched for variables
|
* @param array $vars The array containing the variables with their values
|
||||||
* @param array $vars
|
|
||||||
* The array containing the variables with their values
|
|
||||||
*
|
*
|
||||||
* @return string The submitted string with the variables replaced.
|
* @return string The submitted string with the variables replaced.
|
||||||
*/
|
*/
|
||||||
public static function replaceVariables($text, $vars)
|
public static function replaceVariables(string $text, array $vars): string
|
||||||
{
|
{
|
||||||
$pattern = "/\{([a-zA-Z0-9\-_]+)\}/";
|
$pattern = "/\{([a-zA-Z0-9\-_]+)\}/";
|
||||||
$matches = [];
|
$matches = [];
|
||||||
@@ -386,12 +403,22 @@ class PhpHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$text = str_replace('\n', "\n", $text);
|
return str_replace('\n', "\n", $text);
|
||||||
return $text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function recursive_array_search($needle, $haystack, &$keys = [], $currentKey = '')
|
/**
|
||||||
{
|
* @param string $needle
|
||||||
|
* @param array $haystack
|
||||||
|
* @param array $keys
|
||||||
|
* @param string $currentKey
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
public static function recursive_array_search(
|
||||||
|
string $needle,
|
||||||
|
array $haystack,
|
||||||
|
array &$keys = [],
|
||||||
|
string $currentKey = ''
|
||||||
|
): bool {
|
||||||
foreach ($haystack as $key => $value) {
|
foreach ($haystack as $key => $value) {
|
||||||
$pathkey = empty($currentKey) ? $key : $currentKey . '.' . $key;
|
$pathkey = empty($currentKey) ? $key : $currentKey . '.' . $key;
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
@@ -406,13 +433,13 @@ class PhpHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* function to check a super-global passed by reference
|
* function to check a super-global passed by reference,
|
||||||
* so it gets automatically updated
|
* so it gets automatically updated
|
||||||
*
|
*
|
||||||
* @param array $global
|
* @param array $global
|
||||||
* @param AntiXSS $antiXss
|
* @param AntiXSS $antiXss
|
||||||
*/
|
*/
|
||||||
public static function cleanGlobal(&$global, &$antiXss)
|
public static function cleanGlobal(array &$global, AntiXSS &$antiXss)
|
||||||
{
|
{
|
||||||
$ignored_fields = [
|
$ignored_fields = [
|
||||||
'system_default_vhostconf',
|
'system_default_vhostconf',
|
||||||
@@ -434,7 +461,12 @@ class PhpHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function sortListByGivenKey($a, $b): int
|
/**
|
||||||
|
* @param array $a
|
||||||
|
* @param array $b
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private static function sortListByGivenKey(array $a, array $b): int
|
||||||
{
|
{
|
||||||
if (self::$sort_type == SORT_NATURAL) {
|
if (self::$sort_type == SORT_NATURAL) {
|
||||||
return strnatcasecmp($a[self::$sort_key], $b[self::$sort_key]);
|
return strnatcasecmp($a[self::$sort_key], $b[self::$sort_key]);
|
||||||
@@ -467,15 +499,14 @@ class PhpHelper
|
|||||||
/**
|
/**
|
||||||
* Parse array to array string.
|
* Parse array to array string.
|
||||||
*
|
*
|
||||||
* @param $array
|
* @param array $array
|
||||||
* @param $key
|
* @param ?string $key
|
||||||
* @param int $depth
|
* @param int $depth
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function parseArrayToString($array, $key = null, int $depth = 1): string
|
public static function parseArrayToString(array $array, string $key = null, int $depth = 1): string
|
||||||
{
|
{
|
||||||
$str = '';
|
$str = '';
|
||||||
if (is_array($array)) {
|
|
||||||
if (!is_null($key)) {
|
if (!is_null($key)) {
|
||||||
$str .= self::tabPrefix(($depth - 1), "'{$key}' => [\n");
|
$str .= self::tabPrefix(($depth - 1), "'{$key}' => [\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -487,15 +518,19 @@ class PhpHelper
|
|||||||
$str .= self::tabPrefix($depth, sprintf("'%s' => %s,\n", $key, $value ? 'true' : 'false'));
|
$str .= self::tabPrefix($depth, sprintf("'%s' => %s,\n", $key, $value ? 'true' : 'false'));
|
||||||
} elseif (is_int($value)) {
|
} elseif (is_int($value)) {
|
||||||
$str .= self::tabPrefix($depth, "'{$key}' => $value,\n");
|
$str .= self::tabPrefix($depth, "'{$key}' => $value,\n");
|
||||||
|
} else {
|
||||||
|
if ($key == 'password') {
|
||||||
|
// special case for passwords (nowdoc)
|
||||||
|
$str .= self::tabPrefix($depth, "'{$key}' => <<<'EOT'\n{$value}\nEOT,\n");
|
||||||
} else {
|
} else {
|
||||||
$str .= self::tabPrefix($depth, "'{$key}' => '{$value}',\n");
|
$str .= self::tabPrefix($depth, "'{$key}' => '{$value}',\n");
|
||||||
}
|
}
|
||||||
} elseif (is_array($value)) {
|
}
|
||||||
|
} else {
|
||||||
$str .= self::parseArrayToString($value, $key, ($depth + 1));
|
$str .= self::parseArrayToString($value, $key, ($depth + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$str .= self::tabPrefix(($depth - 1), "],\n");
|
$str .= self::tabPrefix(($depth - 1), "],\n");
|
||||||
}
|
|
||||||
return $str;
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ namespace Froxlor;
|
|||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\UI\Form;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
use PDO;
|
use PDO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,14 +81,16 @@ class SImExporter
|
|||||||
$_data[$index] = $row['value'];
|
$_data[$index] = $row['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists($row['settinggroup'], $settings_definitions) && array_key_exists($row['varname'], $settings_definitions[$row['settinggroup']])) {
|
if (array_key_exists($row['settinggroup'], $settings_definitions) && array_key_exists($row['varname'],
|
||||||
|
$settings_definitions[$row['settinggroup']])) {
|
||||||
// Export image file
|
// Export image file
|
||||||
if ($settings_definitions[$row['settinggroup']][$row['varname']]['type'] === "image") {
|
if ($settings_definitions[$row['settinggroup']][$row['varname']]['type'] === "image") {
|
||||||
if ($row['value'] === "") {
|
if ($row['value'] === "") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$_data[$index . '.image_data'] = base64_encode(file_get_contents(explode('?', $row['value'], 2)[0]));
|
$_data[$index . '.image_data'] = base64_encode(file_get_contents(explode('?', $row['value'],
|
||||||
|
2)[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,12 +144,44 @@ class SImExporter
|
|||||||
$_data['system.le_froxlor_redirect'] = 0;
|
$_data['system.le_froxlor_redirect'] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// store new data
|
|
||||||
foreach ($_data as $index => $value) {
|
|
||||||
$index_split = explode('.', $index, 3);
|
|
||||||
|
|
||||||
// Catch image_data and save it
|
$form_data = [];
|
||||||
|
$image_data = [];
|
||||||
|
// read in all current settings
|
||||||
|
$current_settings = Settings::getAll();
|
||||||
|
foreach ($current_settings as $setting_group => $setting) {
|
||||||
|
foreach ($setting as $varname => $value) {
|
||||||
|
// set all group/varname:values which are not in the import file
|
||||||
|
if (!array_key_exists($setting_group . '.' . $varname, $_data)) {
|
||||||
|
$_data[$setting_group . '.' . $varname] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// re-format the array-key for Form::processForm
|
||||||
|
foreach ($_data as $key => $value) {
|
||||||
|
$index_split = explode('.', $key, 3);
|
||||||
|
if (!isset($current_settings[$index_split[0]][$index_split[1]])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (isset($index_split[2]) && $index_split[2] === 'image_data' && !empty($_data[$index_split[0] . '.' . $index_split[1]])) {
|
if (isset($index_split[2]) && $index_split[2] === 'image_data' && !empty($_data[$index_split[0] . '.' . $index_split[1]])) {
|
||||||
|
$image_data[$key] = $value;
|
||||||
|
} else {
|
||||||
|
$form_data[str_replace(".", "_", $key)] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// store new data
|
||||||
|
$settings_data = PhpHelper::loadConfigArrayDir(Froxlor::getInstallDir() . '/actions/admin/settings/');
|
||||||
|
Settings::loadSettingsInto($settings_data);
|
||||||
|
|
||||||
|
if (Form::processForm($settings_data, $form_data, [], null, true)) {
|
||||||
|
// save to DB
|
||||||
|
Settings::Flush();
|
||||||
|
|
||||||
|
// Process image_data and save it
|
||||||
|
if (count($image_data) > 0) {
|
||||||
|
foreach ($image_data as $index => $value) {
|
||||||
|
$index_split = explode('.', $index, 3);
|
||||||
$path = Froxlor::getInstallDir() . '/img/';
|
$path = Froxlor::getInstallDir() . '/img/';
|
||||||
if (!is_dir($path) && !mkdir($path, 0775)) {
|
if (!is_dir($path) && !mkdir($path, 0775)) {
|
||||||
throw new Exception("img directory does not exist and cannot be created");
|
throw new Exception("img directory does not exist and cannot be created");
|
||||||
@@ -158,25 +194,9 @@ class SImExporter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Validate::validateBase64Image($value)) {
|
||||||
$img_data = base64_decode($value);
|
$img_data = base64_decode($value);
|
||||||
$img_filename = Froxlor::getInstallDir() . '/' . str_replace('../', '', explode('?', $_data[$index_split[0] . '.' . $index_split[1]], 2)[0]);
|
$img_filename = explode('?', $_data[$index_split[0] . '.' . $index_split[1]], 2)[0];
|
||||||
|
|
||||||
file_put_contents($img_filename, $img_data);
|
|
||||||
|
|
||||||
if (function_exists('finfo_open')) {
|
|
||||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
|
||||||
$mimetype = finfo_file($finfo, $img_filename);
|
|
||||||
finfo_close($finfo);
|
|
||||||
} else {
|
|
||||||
$mimetype = mime_content_type($img_filename);
|
|
||||||
}
|
|
||||||
if (empty($mimetype)) {
|
|
||||||
$mimetype = 'application/octet-stream';
|
|
||||||
}
|
|
||||||
if (!in_array($mimetype, ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'])) {
|
|
||||||
@unlink($img_filename);
|
|
||||||
throw new Exception("Uploaded file is not a valid image");
|
|
||||||
}
|
|
||||||
|
|
||||||
$spl = explode('.', $img_filename);
|
$spl = explode('.', $img_filename);
|
||||||
$file_extension = strtolower(array_pop($spl));
|
$file_extension = strtolower(array_pop($spl));
|
||||||
@@ -188,18 +208,20 @@ class SImExporter
|
|||||||
'png',
|
'png',
|
||||||
'gif'
|
'gif'
|
||||||
])) {
|
])) {
|
||||||
@unlink($img_filename);
|
|
||||||
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
|
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
|
||||||
}
|
}
|
||||||
continue;
|
$img_filename = 'img/' . bin2hex(random_bytes(16)) . '.' . $file_extension;
|
||||||
|
file_put_contents(Froxlor::getInstallDir() . '/' . $img_filename, $img_data);
|
||||||
|
$img_index = $index_split[0].'.'.$index_split[1];
|
||||||
|
Settings::Set($img_index, $img_filename . '?v=' . time());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::Set($index, $value);
|
|
||||||
}
|
}
|
||||||
// save to DB
|
|
||||||
Settings::Flush();
|
|
||||||
// all good
|
// all good
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Exception("Importing settings failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw new Exception("Invalid JSON data: " . json_last_error_msg());
|
throw new Exception("Invalid JSON data: " . json_last_error_msg());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -329,6 +329,12 @@ class Settings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getAll() : array
|
||||||
|
{
|
||||||
|
self::init();
|
||||||
|
return self::$data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get value from config by identifier
|
* get value from config by identifier
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -30,10 +30,19 @@ use Froxlor\Database\Database;
|
|||||||
class FroxlorVhostSettings
|
class FroxlorVhostSettings
|
||||||
{
|
{
|
||||||
|
|
||||||
public static function hasVhostContainerEnabled($need_ssl = false)
|
/**
|
||||||
|
* @param bool $need_ssl
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function hasVhostContainerEnabled(bool $need_ssl = false): bool
|
||||||
{
|
{
|
||||||
$sel_stmt = Database::prepare("SELECT COUNT(*) as vcentries FROM `" . TABLE_PANEL_IPSANDPORTS . "` WHERE `vhostcontainer`= '1'" . ($need_ssl ? " AND `ssl` = '1'" : ""));
|
$sel_stmt = Database::prepare("SELECT COUNT(*) as vcentries FROM `" . TABLE_PANEL_IPSANDPORTS . "` WHERE `vhostcontainer`= '1'" . ($need_ssl ? " AND `ssl` = '1'" : ""));
|
||||||
$result = Database::pexecute_first($sel_stmt);
|
$result = Database::pexecute_first($sel_stmt);
|
||||||
|
if ($result) {
|
||||||
return $result['vcentries'] > 0;
|
return $result['vcentries'] > 0;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ use Froxlor\PhpHelper;
|
|||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\IPTools;
|
use Froxlor\System\IPTools;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
use PDO;
|
use PDO;
|
||||||
|
|
||||||
class Store
|
class Store
|
||||||
@@ -45,10 +46,21 @@ class Store
|
|||||||
{
|
{
|
||||||
$returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue);
|
$returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue);
|
||||||
|
|
||||||
if ($returnvalue !== false && is_array($fielddata) && isset($fielddata['settinggroup']) && $fielddata['settinggroup'] == 'system' && isset($fielddata['varname']) && $fielddata['varname'] == 'le_froxlor_enabled' && $newfieldvalue == '0') {
|
if ($returnvalue !== false
|
||||||
|
&& is_array($fielddata)
|
||||||
|
&& isset($fielddata['settinggroup'])
|
||||||
|
&& $fielddata['settinggroup'] == 'system'
|
||||||
|
&& isset($fielddata['varname'])
|
||||||
|
) {
|
||||||
|
if ($fielddata['varname'] == 'le_froxlor_enabled' && $newfieldvalue == '0') {
|
||||||
Database::query("
|
Database::query("
|
||||||
DELETE FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = '0'
|
DELETE FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = '0'
|
||||||
");
|
");
|
||||||
|
} elseif ($fielddata['varname'] == 'froxloraliases' && $newfieldvalue != $fielddata['value']) {
|
||||||
|
Database::query("
|
||||||
|
UPDATE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` SET `validtodate`= NULL WHERE `domainid` = '0'
|
||||||
|
");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $returnvalue;
|
return $returnvalue;
|
||||||
@@ -415,22 +427,12 @@ class Store
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure mime-type matches an image
|
// Make sure mime-type matches an image
|
||||||
if (function_exists('finfo_open')) {
|
$image_content = file_get_contents($_FILES[$fieldname]['tmp_name']);
|
||||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
$value = base64_encode($image_content);
|
||||||
$mimetype = finfo_file($finfo, $_FILES[$fieldname]['tmp_name']);
|
if (Validate::validateBase64Image($value)) {
|
||||||
finfo_close($finfo);
|
$img_filename = $_FILES[$fieldname]['name'];
|
||||||
} else {
|
|
||||||
$mimetype = mime_content_type($_FILES[$fieldname]['tmp_name']);
|
|
||||||
}
|
|
||||||
if (empty($mimetype)) {
|
|
||||||
$mimetype = 'application/octet-stream';
|
|
||||||
}
|
|
||||||
if (!in_array($mimetype, ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'])) {
|
|
||||||
throw new \Exception("Uploaded file is not a valid image");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine file extension
|
$spl = explode('.', $img_filename);
|
||||||
$spl = explode('.', $_FILES[$fieldname]['name']);
|
|
||||||
$file_extension = strtolower(array_pop($spl));
|
$file_extension = strtolower(array_pop($spl));
|
||||||
unset($spl);
|
unset($spl);
|
||||||
|
|
||||||
@@ -442,13 +444,13 @@ class Store
|
|||||||
])) {
|
])) {
|
||||||
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
|
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
|
||||||
}
|
}
|
||||||
|
$filename = bin2hex(random_bytes(16)) . '.' . $file_extension;
|
||||||
// Move file
|
// Move file
|
||||||
if (!move_uploaded_file($_FILES[$fieldname]['tmp_name'], $path . $fielddata['image_name'] . '.' . $file_extension)) {
|
if (!move_uploaded_file($_FILES[$fieldname]['tmp_name'], $path . $filename)) {
|
||||||
throw new Exception("Unable to save image to img folder");
|
throw new Exception("Unable to save image to img folder");
|
||||||
}
|
}
|
||||||
|
$save_to = 'img/' . $filename . '?v=' . time();
|
||||||
$save_to = 'img/' . $fielddata['image_name'] . '.' . $file_extension . '?v=' . time();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete file?
|
// Delete file?
|
||||||
|
|||||||
@@ -100,32 +100,34 @@ class Cronjob
|
|||||||
|
|
||||||
// now check if it differs from our settings
|
// now check if it differs from our settings
|
||||||
if ($update_to_guid != Settings::Get('system.lastguid')) {
|
if ($update_to_guid != Settings::Get('system.lastguid')) {
|
||||||
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Updating froxlor last guid to ' . $update_to_guid);
|
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE,
|
||||||
|
'Updating froxlor last guid to ' . $update_to_guid);
|
||||||
Settings::Set('system.lastguid', $update_to_guid);
|
Settings::Set('system.lastguid', $update_to_guid);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'File /etc/group not readable; cannot check for latest guid');
|
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE,
|
||||||
|
'File /etc/group not readable; cannot check for latest guid');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'File /etc/group not readable; cannot check for latest guid');
|
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE,
|
||||||
|
'File /etc/group not readable; cannot check for latest guid');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'File /etc/group does not exist; cannot check for latest guid');
|
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE,
|
||||||
|
'File /etc/group does not exist; cannot check for latest guid');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a task into the PANEL_TASKS-Table
|
* Inserts a task into the PANEL_TASKS-Table
|
||||||
*
|
*
|
||||||
* @param
|
* @param int $type Type of task
|
||||||
* int Type of task
|
* @param string $params Parameter (possible to pass multiple times)
|
||||||
* @param
|
|
||||||
* string Parameter (possible to pass multiple times)
|
|
||||||
*
|
*
|
||||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
* @throws Exception
|
||||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||||
*/
|
*/
|
||||||
public static function inserttask($type, ...$params)
|
public static function inserttask(int $type, ...$params)
|
||||||
{
|
{
|
||||||
// prepare the insert-statement
|
// prepare the insert-statement
|
||||||
$ins_stmt = Database::prepare("
|
$ins_stmt = Database::prepare("
|
||||||
@@ -223,7 +225,7 @@ class Cronjob
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function getCronjobsLastRun()
|
public static function getCronjobsLastRun(): array
|
||||||
{
|
{
|
||||||
$query = "SELECT `lastrun`, `desc_lng_key` FROM `" . TABLE_PANEL_CRONRUNS . "` WHERE `isactive` = '1' ORDER BY `cronfile` ASC";
|
$query = "SELECT `lastrun`, `desc_lng_key` FROM `" . TABLE_PANEL_CRONRUNS . "` WHERE `isactive` = '1' ORDER BY `cronfile` ASC";
|
||||||
$result = Database::query($query);
|
$result = Database::query($query);
|
||||||
@@ -238,14 +240,21 @@ class Cronjob
|
|||||||
return $cronjobs_last_run;
|
return $cronjobs_last_run;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function toggleCronStatus($module = null, $isactive = 0)
|
/**
|
||||||
|
* @param string $module
|
||||||
|
* @param int $isactive
|
||||||
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function toggleCronStatus(string $module, int $isactive = 0)
|
||||||
{
|
{
|
||||||
if ($isactive != 1) {
|
if ($isactive != 1) {
|
||||||
$isactive = 0;
|
$isactive = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$upd_stmt = Database::prepare("
|
$upd_stmt = Database::prepare("
|
||||||
UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET `isactive` = :active WHERE `module` = :module");
|
UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET `isactive` = :active WHERE `module` = :module
|
||||||
|
");
|
||||||
Database::pexecute($upd_stmt, [
|
Database::pexecute($upd_stmt, [
|
||||||
'active' => $isactive,
|
'active' => $isactive,
|
||||||
'module' => $module
|
'module' => $module
|
||||||
@@ -257,7 +266,7 @@ class Cronjob
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function getOutstandingTasks()
|
public static function getOutstandingTasks(): array
|
||||||
{
|
{
|
||||||
$query = "SELECT * FROM `" . TABLE_PANEL_TASKS . "` ORDER BY `type` ASC";
|
$query = "SELECT * FROM `" . TABLE_PANEL_TASKS . "` ORDER BY `type` ASC";
|
||||||
$result = Database::query($query);
|
$result = Database::query($query);
|
||||||
@@ -309,7 +318,7 @@ class Cronjob
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function dieWithMail($message, $subject = "[froxlor] Cronjob error")
|
public static function dieWithMail(string $message, string $subject = "[froxlor] Cronjob error")
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.send_cron_errors') == '1') {
|
if (Settings::Get('system.send_cron_errors') == '1') {
|
||||||
$_mail = new Mailer(true);
|
$_mail = new Mailer(true);
|
||||||
@@ -339,7 +348,12 @@ class Cronjob
|
|||||||
die($message);
|
die($message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function updateLastRunOfCron($cronname)
|
/**
|
||||||
|
* @param string $cronname
|
||||||
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function updateLastRunOfCron(string $cronname)
|
||||||
{
|
{
|
||||||
$upd_stmt = Database::prepare("
|
$upd_stmt = Database::prepare("
|
||||||
UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET `lastrun` = UNIX_TIMESTAMP() WHERE `cronfile` = :cron;
|
UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET `lastrun` = UNIX_TIMESTAMP() WHERE `cronfile` = :cron;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Crypt
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function generatePassword(int $length = 0, bool $isSalt = false)
|
public static function generatePassword(int $length = 0, bool $isSalt = false): string
|
||||||
{
|
{
|
||||||
$alpha_lower = 'abcdefghijklmnopqrstuvwxyz';
|
$alpha_lower = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
$alpha_upper = strtoupper($alpha_lower);
|
$alpha_upper = strtoupper($alpha_lower);
|
||||||
@@ -78,7 +78,7 @@ class Crypt
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private static function specialShuffle($str = null)
|
private static function specialShuffle(string $str): string
|
||||||
{
|
{
|
||||||
$len = mb_strlen($str);
|
$len = mb_strlen($str);
|
||||||
$sploded = [];
|
$sploded = [];
|
||||||
@@ -94,7 +94,7 @@ class Crypt
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function getAvailablePasswordHashes()
|
public static function getAvailablePasswordHashes(): array
|
||||||
{
|
{
|
||||||
// get available pwd-hases
|
// get available pwd-hases
|
||||||
$available_pwdhashes = [
|
$available_pwdhashes = [
|
||||||
@@ -120,31 +120,40 @@ class Crypt
|
|||||||
* we check against the length, if not matched
|
* we check against the length, if not matched
|
||||||
* an error message will be output and 'exit' is called
|
* an error message will be output and 'exit' is called
|
||||||
*
|
*
|
||||||
* @param string $password
|
* @param string $password the password to validate
|
||||||
* the password to validate
|
* @param bool $json_response
|
||||||
*
|
*
|
||||||
* @return string either the password or an errormessage+exit
|
* @return string either the password or an errormessage+exit
|
||||||
*/
|
*/
|
||||||
public static function validatePassword($password = null, $json_response = false)
|
public static function validatePassword(string $password, bool $json_response = false): string
|
||||||
{
|
{
|
||||||
if (Settings::Get('panel.password_min_length') > 0) {
|
if (Settings::Get('panel.password_min_length') > 0) {
|
||||||
$password = Validate::validate($password, Settings::Get('panel.password_min_length'), '/^.{' . (int)Settings::Get('panel.password_min_length') . ',}$/D', 'notrequiredpasswordlength', [], $json_response);
|
$password = Validate::validate($password, Settings::Get('panel.password_min_length'),
|
||||||
|
'/^.{' . (int)Settings::Get('panel.password_min_length') . ',}$/D', 'notrequiredpasswordlength', [],
|
||||||
|
$json_response);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::Get('panel.password_regex') != '') {
|
if (Settings::Get('panel.password_regex') != '') {
|
||||||
$password = Validate::validate($password, Settings::Get('panel.password_regex'), Settings::Get('panel.password_regex'), 'notrequiredpasswordcomplexity', [], $json_response);
|
$password = Validate::validate($password, Settings::Get('panel.password_regex'),
|
||||||
|
Settings::Get('panel.password_regex'), 'notrequiredpasswordcomplexity', [], $json_response);
|
||||||
} else {
|
} else {
|
||||||
if (Settings::Get('panel.password_alpha_lower')) {
|
if (Settings::Get('panel.password_alpha_lower')) {
|
||||||
$password = Validate::validate($password, '/.*[a-z]+.*/', '/.*[a-z]+.*/', 'notrequiredpasswordcomplexity', [], $json_response);
|
$password = Validate::validate($password, '/.*[a-z]+.*/', '/.*[a-z]+.*/',
|
||||||
|
'notrequiredpasswordcomplexity', [], $json_response);
|
||||||
}
|
}
|
||||||
if (Settings::Get('panel.password_alpha_upper')) {
|
if (Settings::Get('panel.password_alpha_upper')) {
|
||||||
$password = Validate::validate($password, '/.*[A-Z]+.*/', '/.*[A-Z]+.*/', 'notrequiredpasswordcomplexity', [], $json_response);
|
$password = Validate::validate($password, '/.*[A-Z]+.*/', '/.*[A-Z]+.*/',
|
||||||
|
'notrequiredpasswordcomplexity', [], $json_response);
|
||||||
}
|
}
|
||||||
if (Settings::Get('panel.password_numeric')) {
|
if (Settings::Get('panel.password_numeric')) {
|
||||||
$password = Validate::validate($password, '/.*[0-9]+.*/', '/.*[0-9]+.*/', 'notrequiredpasswordcomplexity', [], $json_response);
|
$password = Validate::validate($password, '/.*[0-9]+.*/', '/.*[0-9]+.*/',
|
||||||
|
'notrequiredpasswordcomplexity', [], $json_response);
|
||||||
}
|
}
|
||||||
if (Settings::Get('panel.password_special_char_required')) {
|
if (Settings::Get('panel.password_special_char_required')) {
|
||||||
$password = Validate::validate($password, '/.*[' . preg_quote(Settings::Get('panel.password_special_char'), '/') . ']+.*/', '/.*[' . preg_quote(Settings::Get('panel.password_special_char'), '/') . ']+.*/', 'notrequiredpasswordcomplexity', [], $json_response);
|
$password = Validate::validate($password,
|
||||||
|
'/.*[' . preg_quote(Settings::Get('panel.password_special_char'), '/') . ']+.*/',
|
||||||
|
'/.*[' . preg_quote(Settings::Get('panel.password_special_char'), '/') . ']+.*/',
|
||||||
|
'notrequiredpasswordcomplexity', [], $json_response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,19 +168,20 @@ class Crypt
|
|||||||
* additionally it updates the hash if the system settings changed
|
* additionally it updates the hash if the system settings changed
|
||||||
* or if the very old md5() sum is used
|
* or if the very old md5() sum is used
|
||||||
*
|
*
|
||||||
* @param array $userinfo
|
* @param array $userinfo user-data from table
|
||||||
* user-data from table
|
* @param string $password the password to validate
|
||||||
* @param string $password
|
* @param string $table either panel_customers or panel_admins
|
||||||
* the password to validate
|
* @param string $uid user-id-field in $table
|
||||||
* @param string $table
|
|
||||||
* either panel_customers or panel_admins
|
|
||||||
* @param string $uid
|
|
||||||
* user-id-field in $table
|
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function validatePasswordLogin($userinfo = null, $password = null, $table = 'panel_customers', $uid = 'customerid')
|
public static function validatePasswordLogin(
|
||||||
{
|
array $userinfo,
|
||||||
|
string $password,
|
||||||
|
string $table = 'panel_customers',
|
||||||
|
string $uid = 'customerid'
|
||||||
|
): bool {
|
||||||
$algo = Settings::Get('system.passwordcryptfunc') !== null ? Settings::Get('system.passwordcryptfunc') : PASSWORD_DEFAULT;
|
$algo = Settings::Get('system.passwordcryptfunc') !== null ? Settings::Get('system.passwordcryptfunc') : PASSWORD_DEFAULT;
|
||||||
if (is_numeric($algo)) {
|
if (is_numeric($algo)) {
|
||||||
// old setting format
|
// old setting format
|
||||||
@@ -188,7 +198,7 @@ class Crypt
|
|||||||
$update_hash = true;
|
$update_hash = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($pwd_hash == $pwd_check || password_verify($password, $pwd_hash)) {
|
if ($pwd_hash === $pwd_check || password_verify($password, $pwd_hash)) {
|
||||||
// check for update of hash (only if our database is ready to handle the bigger string)
|
// check for update of hash (only if our database is ready to handle the bigger string)
|
||||||
$is_ready = Froxlor::versionCompare2("0.9.33", Froxlor::getVersion()) <= 0;
|
$is_ready = Froxlor::versionCompare2("0.9.33", Froxlor::getVersion()) <= 0;
|
||||||
if ((password_needs_rehash($pwd_hash, $algo) || $update_hash) && $is_ready) {
|
if ((password_needs_rehash($pwd_hash, $algo) || $update_hash) && $is_ready) {
|
||||||
@@ -209,24 +219,21 @@ class Crypt
|
|||||||
/**
|
/**
|
||||||
* Make encrypted password from clear text password
|
* Make encrypted password from clear text password
|
||||||
*
|
*
|
||||||
* @param string $password
|
* @param string $password Password to be encrypted
|
||||||
* Password to be encrypted
|
* @param bool $htpasswd optional whether to generate a bcrypt password for directory protection
|
||||||
* @param bool $htpasswd
|
* @param bool $ftpd optional generates sha256 password strings for proftpd/pureftpd
|
||||||
* optional whether to generate a SHA1 password for directory protection
|
|
||||||
* @param bool $ftpd
|
|
||||||
* optional generates sha256 password strings for proftpd/pureftpd
|
|
||||||
*
|
*
|
||||||
* @return string encrypted password
|
* @return string encrypted password
|
||||||
*/
|
*/
|
||||||
public static function makeCryptPassword(string $password, bool $htpasswd = false, bool $ftpd = false)
|
public static function makeCryptPassword(string $password, bool $htpasswd = false, bool $ftpd = false): string
|
||||||
{
|
{
|
||||||
if ($htpasswd || $ftpd) {
|
if ($htpasswd || $ftpd) {
|
||||||
if ($ftpd) {
|
if ($ftpd) {
|
||||||
// sha256 compatible for proftpd and pure-ftpd
|
// sha256 compatible for proftpd and pure-ftpd
|
||||||
return crypt($password, '$5$' . self::generatePassword(16, true) . '$');
|
return crypt($password, '$5$' . self::generatePassword(16, true) . '$');
|
||||||
}
|
}
|
||||||
// sha1 hash for dir-protection
|
// bcrypt hash for dir-protection
|
||||||
return '{SHA}' . base64_encode(sha1($password, true));
|
return password_hash($password, PASSWORD_BCRYPT);
|
||||||
}
|
}
|
||||||
// crypt using the specified crypt-algorithm or system default
|
// crypt using the specified crypt-algorithm or system default
|
||||||
$algo = Settings::Get('system.passwordcryptfunc') !== null ? Settings::Get('system.passwordcryptfunc') : PASSWORD_DEFAULT;
|
$algo = Settings::Get('system.passwordcryptfunc') !== null ? Settings::Get('system.passwordcryptfunc') : PASSWORD_DEFAULT;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user