Compare commits

...

215 Commits

Author SHA1 Message Date
Michael Kaufmann
37176c94a1 set version to 0.10.19 for upcoming release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-07-03 14:12:48 +02:00
Michael Kaufmann
a141c83ad4 do not call strtotime on the validTo_time_t key of cert_data as it already is an UNIX-timestamp, refs #865
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-23 20:35:50 +02:00
Michael Kaufmann
7c3ff95d22 check for possible CNAME overrides of A/AAAA record in dns-editor, fixes #864
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-23 09:39:00 +02:00
Michael Kaufmann
d653f6842f check for acme.sh upgrade on every run; fix not running --install-cronjob without having an issue command
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-21 19:50:46 +02:00
Michael Kaufmann
35a69fbfe0 add missing parmeter customerid for SubDomains.delete() which is required when called as admin; fixes #862
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-18 13:05:17 +02:00
Michael Kaufmann
e733701459 trigger removal cronjob of lets encrypt certificate via acme.sh also when domain update removes letsencrypt flag from domain
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-17 14:09:26 +02:00
Michael Kaufmann
70677fced2 fix double-adding of _ecc to certificate folder when deleting let's encrypt certificate
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-17 12:08:54 +02:00
Michael Kaufmann
daa223ed42 return full domain object on Domains.update() call, fixes #861
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-17 09:29:02 +02:00
Michael Kaufmann
0398f4cdba set version to 0.10.18 for upcoming release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-12 15:17:09 +02:00
Michael Kaufmann
1a0953e77e fix typo in response status message, fixes #858
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-08 11:42:44 +02:00
Michael Kaufmann
490704f8e1 Heredoc/nowdoc with an indented closing marker is not supported in PHP 7.2 or earlier.
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-06 20:57:24 +02:00
Michael Kaufmann
2748f1b633 also display error when domain does not resolv to any A or AAAA record in lets-encrypt-dns-validation
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-06 15:37:06 +02:00
Michael Kaufmann
8e60c6b201 update api documentation for Ftps.update(), fixes #857
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-05 16:23:41 +02:00
Michael Kaufmann
d4716b2376 correct documentation for Customers.add(), fixes #856
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-05 15:33:49 +02:00
Michael Kaufmann
2c98fc4c2d fix wrong certificate folder for fallback ceck (ecc/non-ecc)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-06-04 07:42:13 +02:00
Michael Kaufmann
65e1f633ef Merge pull request #855 from daxara/detect_distr
Auto detection in CLI & checks
2020-05-31 20:59:26 +02:00
Ante de Baas
ed4dbba278 also perform checks in Install class 2020-05-31 20:46:27 +02:00
Ante de Baas
1a6082ca91 complete if statement 2020-05-31 20:36:52 +02:00
Ante de Baas
da1d94149a saet defaults and do some checks 2020-05-31 20:34:47 +02:00
Ante de Baas
e7cfceb65d add comment 2020-05-31 20:18:37 +02:00
Ante de Baas
1f48ca4711 autodeterct distribution in CLI 2020-05-31 20:10:07 +02:00
Michael Kaufmann
fe0fb8dd5f fix non-static method called statically in \Froxlor\FileDir
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-31 16:38:53 +02:00
Michael Kaufmann
4a5ab7d95d Merge pull request #854 from daxara/detect_distr
fix bugs in dist detection
2020-05-31 16:36:52 +02:00
Ante de Baas
0d44adf265 fix bugs is dist detection 2020-05-31 16:00:50 +02:00
Michael Kaufmann
0b63b4e110 Merge pull request #853 from daxara/centos7
[centos7] proftp requires epel, awstats needs install and awstats cron moved
2020-05-31 15:02:57 +02:00
Michael Kaufmann
ba7e9688c5 Merge pull request #852 from daxara/centos8
Centos8 config updated
2020-05-31 15:02:31 +02:00
Ante de Baas
443ae1df68 proftp requires epel, awstats needs install and awstats cron moved 2020-05-31 14:57:07 +02:00
Ante de Baas
b59aa6f140 undo dnf -y 2020-05-31 14:28:37 +02:00
Ante de Baas
4e9df61fef awstats cron is moved to cron.hourly 2020-05-31 13:15:55 +02:00
Ante de Baas
b350815aa0 install awstats and requirements 2020-05-31 13:11:58 +02:00
Ante de Baas
b672c722b9 no user interaction on package installation 2020-05-31 13:05:52 +02:00
Ante de Baas
db60606cfa proftpd requires epel 2020-05-31 12:52:31 +02:00
Ante de Baas
2524491883 centos8 uses 'dandified yum' 2020-05-31 12:47:28 +02:00
Ante de Baas
de061e7e36 add missing apacheconf_htpasswddir dir 2020-05-31 12:46:33 +02:00
Michael Kaufmann
9ecd182a91 Merge pull request #851 from daxara/master
rename rhel7 to centos7 for consistency
2020-05-31 11:26:12 +02:00
Ante de Baas
a7934bcb7b rename rhel7 to centos7 for consistancy 2020-05-31 11:17:43 +02:00
Michael Kaufmann
9dc2c09da7 Merge pull request #850 from daxara/rhel8
Add CentOS 8 configuration-templates
2020-05-31 09:30:51 +02:00
Michael Kaufmann
b23e4a4d85 Merge pull request #849 from daxara/detect_distr
Detect distribution upon installation and set setting-defaults (if any) for that distribution
2020-05-31 09:29:42 +02:00
Michael Kaufmann
394ec4cd4a fix ecc certificate paths
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-31 09:13:22 +02:00
Ante de Baas
6ccfb7efbb remove old code 2020-05-30 10:10:57 +02:00
Ante de Baas
1454d8d40f get defaults from configparser 2020-05-30 10:08:05 +02:00
Ante de Baas
0fde1ce7e9 remove dev comment 2020-05-30 09:15:15 +02:00
Ante de Baas
86155f7a9c use Distribution in german language 2020-05-30 09:11:43 +02:00
Ante de Baas
60578a5d31 rename to CentOS because its most likely to be used 2020-05-29 17:46:38 +02:00
Ante de Baas
7fcacb4637 rename to centos because its most likey to be used 2020-05-29 17:45:37 +02:00
Ante de Baas
fb35fb9a3a read distribution from xml and selection via selectbox 2020-05-29 17:33:48 +02:00
Ante de Baas
6128954231 rename propery to property 2020-05-29 15:54:37 +02:00
Ante de Baas
f4d4490d08 change property tagnames 2020-05-29 15:45:04 +02:00
Ante de Baas
27f0c4eb53 remove distribution names from language files 2020-05-29 15:42:38 +02:00
Ante de Baas
cb1df3a7e0 show failue as nice red message 2020-05-29 15:29:53 +02:00
Ante de Baas
a572ac3914 add rhel8 config file 2020-05-29 15:10:06 +02:00
Ante de Baas
498ff15e98 add redhat defaults 2020-05-29 14:59:48 +02:00
Ante de Baas
022ed1a9a8 add setting defaults per distribution when given 2020-05-29 14:59:40 +02:00
Ante de Baas
814339cc73 Merge branch 'master' into detect_distr 2020-05-29 13:54:36 +02:00
Ante de Baas
0bb48a3cdf fix nginx capitalisation. 2020-05-29 13:45:46 +02:00
Ante de Baas
67d74406bd add os distribution detection 2020-05-29 13:36:31 +02:00
Michael Kaufmann
d73d8da2fd read certificate data folder from acme.sh.env file, fixes #846
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-28 20:08:49 +02:00
Michael Kaufmann
3c7bdcb5e0 Merge pull request #847 from Froxlor/dependabot/composer/phpmailer/phpmailer-6.1.6
Bump phpmailer/phpmailer from 6.1.4 to 6.1.6
2020-05-28 10:47:26 +02:00
dependabot[bot]
c6ac73f74f Bump phpmailer/phpmailer from 6.1.4 to 6.1.6
Bumps [phpmailer/phpmailer](https://github.com/PHPMailer/PHPMailer) from 6.1.4 to 6.1.6.
- [Release notes](https://github.com/PHPMailer/PHPMailer/releases)
- [Changelog](https://github.com/PHPMailer/PHPMailer/blob/master/changelog.md)
- [Commits](https://github.com/PHPMailer/PHPMailer/compare/v6.1.4...v6.1.6)

Signed-off-by: dependabot[bot] <support@github.com>
2020-05-27 17:01:04 +00:00
Michael Kaufmann
fdcb294244 Merge pull request #844 from daxara/dns_rhel7
Named DNS for RHEL7
2020-05-25 22:02:40 +02:00
Ante de Baas
8898c7c165 add named dns config 2020-05-25 21:38:58 +02:00
Michael Kaufmann
d4c0acb353 Merge pull request #843 from rubo77/usage
show disk-usage also on unlimited accounts
2020-05-25 09:28:37 +02:00
Ruben Barkow-Kuder
9ea32b69cb show disk-usage also on unlimited accounts
Signed-off-by: Ruben Barkow-Kuder <github@r.z11.de>
2020-05-25 03:14:38 +02:00
Michael Kaufmann
0524c70d2b add config-templates for ubuntu focal (partly tested only for now)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-24 12:16:17 +02:00
Michael Kaufmann
6ca7920147 fix missing language files in config-services cli script; set ubuntu xenial deprecated, remove Ubuntu trusty; fix a2dismod command in buster config-template as php7.3 is default
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-24 11:55:20 +02:00
Michael Kaufmann
65b2e4efa7 do not check for mariadb.sys user on mariadb-10.4 when testing with travis
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-23 21:17:43 +02:00
Michael Kaufmann
7000fd2c30 Merge pull request #841 from rubo77/patch-1
Don't suggest php5 during update as default
2020-05-23 21:16:39 +02:00
Ruben Barkow-Kuder
3b1ff03b33 Don't suggest php5 during update as default 2020-05-23 20:12:27 +02:00
Michael Kaufmann
ffa9205f95 fix sql query to remove duplicates before setting unique key in updater, fixes #840
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-18 20:48:56 +02:00
Michael Kaufmann
bc73ed0c75 adjust tls default value to tlsv1.2; refs #839
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-18 20:48:04 +02:00
Michael Kaufmann
17fd350d33 Merge pull request #839 from negrusti/patch-2
TLSv1 is deprecated
2020-05-18 20:07:30 +02:00
Grigory Morozov
c2e57dfd60 TLSv1 is deprecated 2020-05-18 05:18:42 +07:00
Michael Kaufmann
50f2047da3 set version to 0.10.17 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-15 20:35:25 +02:00
Michael Kaufmann
ecb9470b65 fix including of language-strings in reports-cron, fixes #836
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-15 15:16:24 +02:00
Michael Kaufmann
6d90b5ba80 remove leftover GROUP BY from testing
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-15 09:56:24 +02:00
Michael Kaufmann
eb3590dc34 add unique-key domainid to domain_ssl_settings table
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-15 09:49:53 +02:00
Michael Kaufmann
bddf9b496c enable internal api-call to bypass customer_hide_options check in certain situations where it is needed, fixes #803
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-15 09:35:20 +02:00
Michael Kaufmann
edc702dafa check for required min version of php every time (frontend and cron), fixes #833
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-08 10:03:01 +02:00
Michael Kaufmann
85dfc1030a Merge pull request #832 from RipClaw2971/bugfix
Certificate file cannot be read to database
2020-05-04 16:11:42 +02:00
Andreas Grundler
c0dd432916 Certificate file cannot be read to database if the domain contains capital letters. 2020-05-04 12:08:20 +02:00
Michael Kaufmann
b3db4dd887 set version to 0.10.16 for upcoming release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-05-01 16:27:23 +02:00
Michael Kaufmann
14413a3e8d try to fix travis irc notifications again
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-04-30 20:10:52 +02:00
Michael Kaufmann
a02a081c6b try to fix travis irc notifications
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-04-30 20:03:54 +02:00
Michael Kaufmann
43070e4808 remove possible trailing slash of apache DocumentRoot diretives as sugggested by the httpd-docs, thx to jonbert
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-04-30 19:49:20 +02:00
Michael Kaufmann
98c636c282 let send-to-alternative-email be optional if no address is given instead of displaying error that the email address is invalid; fixes #829
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-04-30 13:03:19 +02:00
Michael Kaufmann
8dace6eca5 remove special characters from name when generating extrausers file
add froxlor hostname to 2fa-qrcode; refs #814

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-04-28 07:59:37 +02:00
Michael Kaufmann
78fc4f84b2 add optional dns validation for let's encrypt activated domains; fixes #817
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-04-14 10:28:33 +02:00
Michael Kaufmann
9018404faa Double check whether installation of acme.sh worked when not installed yet and do not continue if not; fixes #823
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-04-14 08:10:36 +02:00
Michael Kaufmann
8bdd843bd9 fix renew of froxlors own letsencrypt certificate; fix only variables should be passed by reference in BackupCron; fix possible notice or double inclusion of language file in ReportsCron
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-04-08 09:07:48 +02:00
Michael Kaufmann
0d35f5cb29 restructure acmesh implementation and let acme.sh take care of renewing the certificates itself; fixes #792, fixes #816
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-04-04 18:04:39 +02:00
Michael Kaufmann
6815c1c20b Merge pull request #821 from chrschn/master
Fix renewal of ECC/ECDSA certificates.
2020-03-29 23:52:34 +02:00
Christian Schneider
048e6c13ae Fix renewal of ECC/ECDSA certificates.
The ACME v2 implementation uses separate directoies for ECC and on-ECC
certificates. The renew command for a domain checks if an ECC directory
exists (having a "_ecc" suffix) and refuses the command unless the
"--ecc" flag was specified.

Confusingly, this flag is only required to *renew* an ECC certificate,
but not to issue it.

This fixes https://github.com/Froxlor/Froxlor/issues/820.
2020-03-29 22:36:26 +02:00
Michael Kaufmann
aedb829a74 Merge pull request #819 from HBerni/hberni-p0002
fixed parsing due to changes in dovecots default mail_log_prefix
2020-03-21 17:36:00 +01:00
HBerni
4745581720 fixed parsing due to changes in dovecots default mail_log_prefix
regex supports old and new default format now
(see https://wiki2.dovecot.org/Upgrading/2.3)
2020-03-21 16:39:01 +01:00
Michael Kaufmann
489ccbe07a fix removing ip address if ip is set as system-ipaddress but there are other entries of that ip with a different port
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-12 07:01:26 +01:00
Michael Kaufmann
a46e7a3bc4 set correct umask to create user config in installation
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-10 07:48:35 +01:00
Michael Kaufmann
a4431e25d3 remove ssl-certificates connected to domains that are being deleted when deleting a customer; fixes #818
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-10 07:36:22 +01:00
Michael Kaufmann
1fe9f1e9d6 fix language strings for cron cmdline setting and fallback to php binary if no setting is found
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-08 10:30:33 +01:00
Michael Kaufmann
13767df562 set version to 0.10.15 for bugfix release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-08 07:39:39 +01:00
Michael Kaufmann
02c5f80854 correct chmod value for userdata.inc.php file to be written on installation; fixes #815
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-08 07:35:19 +01:00
Michael Kaufmann
d7550ae58a fix deactivated check in api
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-06 22:10:01 +01:00
Michael Kaufmann
cf2c7fa31c deny api access to deactivated users with valid api-key
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-06 22:03:41 +01:00
Michael Kaufmann
32b6285589 set version to 0.10.14 for upcoming release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-06 20:47:20 +01:00
Michael Kaufmann
7e361274c5 forgot one escapeshellarg() and enhanced security on userdata.inc.php creation when installing
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-06 20:44:17 +01:00
Michael Kaufmann
62ce21c9ec secure shell-execution of mysqldump on installation if given database-name exists
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-04 19:35:57 +01:00
Michael Kaufmann
6b09720ef8 use unpredictable tmpfile-name in installation if lib/userdata.inc.php cannot be written due to permission
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-04 19:34:18 +01:00
Michael Kaufmann
8807ae7dad allow private ip ranges in ips-and-ports as some configurations require that; fixes #802
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-02 09:51:44 +01:00
Michael Kaufmann
5f3f208534 remove superfluous comma in sql query which causes invalid sql
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-03-01 09:16:47 +01:00
Michael Kaufmann
f11ceacf89 store ace-string of domain besides idn-converted string to have correct sorting in the frontend; fixes #809
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-02-29 09:50:29 +01:00
Michael Kaufmann
26e43077c2 make customer firstname,name,company and customer-no available for all templates; fixes #808
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-02-29 08:16:55 +01:00
Michael Kaufmann
d6c8b92523 add Froxlor.integrityCheck() API call to externally run integrity/consistency check, fixes #801
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-02-15 07:30:56 +01:00
Michael Kaufmann
03450dcfa2 fix listing of customer email addresses if 'domain' section is hidden via settings, fixes #803
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-02-15 07:25:23 +01:00
Michael Kaufmann
f39aab6f32 disable sslsessiontickets-option in domain-add/edit if globally disabled in the settings
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-02-15 07:11:28 +01:00
Michael Kaufmann
7f999302fa do not require enabled vhost-container for froxlor-vhost to change sslsessiontickets-setting
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-02-14 19:26:06 +01:00
Michael Kaufmann
8294985588 require set password complexity for admins too when resetting password; display correct error message if password complexity is not satisfied
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-02-08 10:03:41 +01:00
Michael Kaufmann
a7653551b2 set version to 0.10.13 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-02-07 16:37:06 +01:00
Michael Kaufmann
734c02e33f update php-fpm defaults; update paths for current stable php-7.3; read froxlor default php.ini from file rather then using phpconfig with id=1; fixes #796
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-31 13:17:49 +01:00
Michael Kaufmann
ace18cb7c9 use correct default-versions for configuration-step to disable mod_php for debian buster and ubuntu bionic
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-31 12:58:04 +01:00
Michael Kaufmann
1270204cd9 fix wrongly initialized resource-usage when re-calculating it; fixes #797
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-31 09:49:29 +01:00
Michael Kaufmann
2831923708 Merge pull request #795 from lpedretti/master
Fixed the case that the spf record is not inserted with it's quotes, and so the condition fails and 2 spf records are inserted in the domain
2020-01-24 16:58:10 +01:00
Leonardo Pedretti
6b1ae648b4 Fixed the case that the spf record is not inserted with it's quotes, and so the condition fails and 2 spf records are inserted in the domain 2020-01-23 11:59:28 -03:00
Michael Kaufmann
6c43f1bc56 fix Domains.update() if called as admin/reseller without change_serversettings privileges, thx to rseffner
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-22 09:14:07 +01:00
Michael Kaufmann
2e273a41b5 fix IpsAndPorts when checking for system.ipaddress in update() and delete()
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-19 10:45:48 +01:00
Michael Kaufmann
2004bbe38d dont access db result arrays directly without checking whether it's false due to an error (php7.4 related)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-19 10:13:28 +01:00
Michael Kaufmann
e44e07784f validate nameserver ip-addresses for binds allow-transfer block; fixes #791
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-19 10:08:06 +01:00
Michael Kaufmann
8d6275e1aa set version to 0.10.12 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-10 17:41:20 +01:00
Michael Kaufmann
f21d4f8770 when not using awstats, disable awstats-related settings; add minor tweaks to unit-tests
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-10 16:44:13 +01:00
Michael Kaufmann
fc97b4d4e9 Merge pull request #786 from patschi/logformat-awstats
Allow configuring awstats LogFormat
2020-01-10 16:32:33 +01:00
Patrik Kernstock
05051309c7 Merge branch 'master' into logformat-awstats 2020-01-09 23:24:26 +00:00
Patrik Kernstock
0f025a6627 Language file update
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2020-01-09 23:21:11 +00:00
Michael Kaufmann
f6f5765b54 avoid settig more than one catchall address for one domain in Emails.update(), thx to mrairstone
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-09 14:45:51 +01:00
Michael Kaufmann
ac82aa80d2 correct logfiles_format migration; only needed if setting is non-empty
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-09 14:14:04 +01:00
Michael Kaufmann
57503d9c6e try to touch logfile from settings in order for is_writable to work correctly, thx to rubberduck
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-09 14:10:50 +01:00
Michael Kaufmann
f55ad16d82 Merge pull request #785 from patschi/logformat
Allow using more advanced webserver LogFormat
2020-01-09 09:16:03 +01:00
Patrik Kernstock
ea7834c1d1 Added small notice to lng for awstats LogFormat
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2020-01-08 22:08:15 +00:00
Patrik Kernstock
b355711de9 Improvements as suggested by @d00p
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2020-01-08 22:08:15 +00:00
Michael Kaufmann
a5287726a4 fix issue in PhpHelper::trimArray() returning an empty array, fixes #751
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-03 23:32:21 +01:00
Patrik Kernstock
b393c7d6e6 Merge branch 'master' into logformat 2020-01-03 22:32:45 +01:00
Michael Kaufmann
dd2782771a set version to 0.10.11 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-03 13:24:31 +01:00
Michael Kaufmann
25d0bbb766 switch from algo26-matthias/idna-covert to our own fork as we cannot update to >2.1 without having a minimum requirement for php-7.2 but we need a few fixes for php-7.4 support later on
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-03 12:48:01 +01:00
Michael Kaufmann
b4dedca3db Update README.md 2020-01-02 13:53:22 +01:00
Patrik Kernstock
09aed61dbf Merge branch 'master' into logformat-awstats 2020-01-02 12:44:35 +01:00
Patrik Kernstock
ca39501530 Fixed awstats_logformat field for new installs
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2020-01-02 12:39:25 +01:00
Patrik Kernstock
28fd88e53e Merge branch 'master' into logformat 2020-01-02 12:31:51 +01:00
Michael Kaufmann
e01c2e02fb fix update query for new fpm-custom_config value, refs #783
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2020-01-02 12:28:48 +01:00
Michael Kaufmann
762bfae61a Merge pull request #783 from patschi/phpfpm-custom-settings
Ability to add custom config to PHPFPM version
2020-01-02 10:19:19 +01:00
Patrik Kernstock
a4d4e16efc Small comment added to escaping double-quote
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2019-12-31 22:46:03 +01:00
Patrik Kernstock
7f83ad31f4 Fixed dbversion in SQL/Froxlor.php
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2019-12-31 22:30:54 +01:00
Patrik Kernstock
e143ba4577 Allow configuring awstats LogFormat
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2019-12-31 22:29:29 +01:00
Patrik Kernstock
6799a56ba1 Allow using more advanced LogFormat
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2019-12-31 20:18:52 +01:00
Patrik Kernstock
484fe8acbc Fixed db_DBVERISON in Froxlor.php
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2019-12-31 17:22:37 +01:00
Patrik Kernstock
550af5b943 Fixed german lng, fixed db_version in SQL
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2019-12-31 17:18:17 +01:00
Patrik Kernstock
7ae59477af New update step, changed order of lang strings
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2019-12-31 16:14:26 +01:00
Michael Kaufmann
acefa41806 Merge pull request #781 from patschi/accesslog-logtype
Use logtype for access_log for IPsAndPorts too
2019-12-31 16:01:42 +01:00
Patrik Kernstock
b39c8029cd Merge branch 'master' into phpfpm-custom-settings 2019-12-31 15:51:27 +01:00
Patrik Kernstock
69ff416361 Fixed SQL, minor comments/lng updates
Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2019-12-31 15:34:46 +01:00
Michael Kaufmann
3eb1718fe0 add option to disable SSL sessiontickets globally for older systems, fixes #784
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-31 12:27:35 +01:00
Michael Kaufmann
37c434d4fc testsystem does not listen on socket for mysql
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-31 09:29:09 +01:00
Michael Kaufmann
1eb14d7564 update composer-dependencies; add connection-test to Mysqls.update() when changing passwords; validate ssl-certificates to avoid private/public key mismatch and a failed webserver start, fixes #778
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-31 09:23:28 +01:00
Michael Kaufmann
1c17df69d2 Merge pull request #782 from patschi/fix-dhparams-indent
Fix dhparam indent
2019-12-31 08:11:40 +01:00
Patrik Kernstock
c61b3b73bd Ability to add custom config to PHPFPM version
Addresses #643

Signed-off-by: Patrik Kernstock <patrik@kernstock.net>
2019-12-31 05:48:36 +01:00
Patrik Kernstock
18c87baec8 Fix dhparam indent 2019-12-31 03:53:12 +01:00
Patrik Kernstock
631b2b59a5 Use logtype for access_log for IPsAndPorts too 2019-12-31 03:51:19 +01:00
Michael Kaufmann
1e0510a43d fix SysLog.delete(), SysLog.listing() and SysLog.listingCount() when called as admin/reseller withouth customers_see_all permission
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-21 15:12:51 +01:00
Michael Kaufmann
e62f675c4c apply 'notryfiles', 'writeaccesslog' and 'writeerrorlog' flags to subdomains when editing a domain
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-18 08:44:02 +01:00
Michael Kaufmann
fe389ab208 setting version to 0.10.10 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-13 16:23:43 +01:00
Michael Kaufmann
63d915804a lowercase domainnames when adding new (sub)domain to avoid issues with certificates on filesystem
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-11 20:12:51 +01:00
Michael Kaufmann
466c09137b add new 'ssl-enabled' flag for domains and subdomains so ssl can be deactivated (by a customer too) even if there are ssl-ip/ports assigned; introduce new honorcipherorder and sessiontickets flags for more control over ssl-related settings on a per domain base (admin only); fixes #767 and fixes #769
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-10 10:21:35 +01:00
Michael Kaufmann
3a738b7070 fix mysql8 issue with group by and sorting within; fixes #774
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-08 10:43:12 +01:00
Michael Kaufmann
5ee9d3064a add new API function Froxlor.generatePassword() to return a random password based on froxlor settings regarding min-length, included characters, etc.; fixes #768
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-06 11:51:40 +01:00
Michael Kaufmann
adb5c6734a set version to 0.10.9 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-06 10:20:01 +01:00
Michael Kaufmann
7dff46b63e set production Lets Encrypt endpoint as default in settings like the installation does; do nat-sorting only on username-related fields, fixes #765
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-05 07:52:11 +01:00
Michael Kaufmann
12883bafd6 check for valid result when reading database usage from information_schema; fixes #766
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-12-04 07:15:28 +01:00
Michael Kaufmann
c2b88200f0 Merge pull request #763 from RipClaw2971/bugfix
SQL error in lib/Froxlor/Api/Commands/Certificates.php
2019-11-29 19:52:13 +01:00
Andreas Grundler
634199780b Bugfix 2019-11-29 19:22:43 +01:00
Michael Kaufmann
e0275840ab set version to 0.10.8 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-29 17:14:02 +01:00
Michael Kaufmann
bae8c86901 fix removing of ssl-ip-relation to domain if no ssl-ip is selected via interface, thx to Patient Nr0
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-27 18:32:27 +01:00
Michael Kaufmann
e8be3ee643 use correct apiendpoint for lets encrypt; pass debug-flag onto acme.sh; fixes #762
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-27 07:42:23 +01:00
Michael Kaufmann
35ecdfa2f5 fix searching for alias-domains by link in customer_domains
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-24 12:52:25 +01:00
Michael Kaufmann
3e4a3ef4b0 fix duplicate domain entries in customer-domain-list when domain has aliases, thx to crazy4chrissi
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-24 11:33:10 +01:00
Michael Kaufmann
cdf02ceab6 set version to 0.10.7 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-22 16:14:13 +01:00
Michael Kaufmann
d24056c925 fix vhost-merging of specialsettings in nginx; fixes #757
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-22 16:12:11 +01:00
Michael Kaufmann
d2852fbd5d add new setting to set default value of domain-edit-setting 'Apply specialsettings to all subdomains' and 'Apply php-config to all subdomains'
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-22 16:10:27 +01:00
Michael Kaufmann
d76ebc7c06 fix sort-ordering parameter for pagination
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-20 13:08:36 +01:00
Michael Kaufmann
4fbaacb159 fix domain listing for admin-domains
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-20 12:20:20 +01:00
Michael Kaufmann
2d43a8714d let's try to fix the mysql-user-create/update issue, fingers crossed; refs #758
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-20 11:06:21 +01:00
Michael Kaufmann
620a22bf3e fix listing of subdomains for customers, fixes #759
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-20 09:33:28 +01:00
Michael Kaufmann
5e01018f30 fix typo in SysLog.delete(), thx to Wolfgang
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-18 14:47:56 +01:00
Michael Kaufmann
c84732a0cd fix issue when adding new database users with already-hashed passwords, refs #758
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-18 10:48:31 +01:00
Michael Kaufmann
dfce1fea3c re-add \Froxlor\UI\Paging as it's still required for api_keys.php because they are not (yet) listable via API
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-17 15:20:46 +01:00
Michael Kaufmann
e6dad6c6d0 Use authentication_string for mysql-5.7 and mysql-8 (not password-field) - let's see what happens
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-17 14:29:37 +01:00
Michael Kaufmann
605d2340d1 first unittest for mysql-users and their password, refs #758
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-17 13:42:35 +01:00
Michael Kaufmann
d5df4dd7a4 set version to 0.10.6 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-15 16:43:36 +01:00
Michael Kaufmann
57497bd03f if no ssl IP/port is selected when editing a domain within the webinterface, set the remove_ssl_ipandport parameter to true to not fallback to defaults
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-15 16:36:14 +01:00
Michael Kaufmann
1a3cc52188 fix parameters defaults for Domains.update() and add new parameter 'remove_ssl_ipandport' to clear ssl ip/port instead of defaulting to the current set value; fixes #756
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-15 15:11:24 +01:00
Michael Kaufmann
21f6874a61 check whether there actually is quota read for a user if newly created, thx again to J-BBB
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-15 12:58:28 +01:00
Michael Kaufmann
b34e66dfd6 fix install-dir replacement in configfiles, thx to J-BBB
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-15 08:02:46 +01:00
Michael Kaufmann
a77f890462 Merge branch 'master' of github.com:Froxlor/Froxlor 2019-11-15 07:20:38 +01:00
Michael Kaufmann
3cc5352c01 implement EmailForwarders.listing(); fixes #754
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-15 07:20:16 +01:00
Michael Kaufmann
d01d470119 Merge pull request #755 from danielrona/patch-1
enabled autofocus for 2fa_code
2019-11-14 12:58:18 +01:00
Daniel
a97ce74cc8 enabled autofocus for 2fa_code 2019-11-14 12:31:29 +01:00
Michael Kaufmann
fe7bfcc7c2 fix update of hosting plans via interface; fixes #753
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-13 15:28:08 +01:00
Michael Kaufmann
cff0ac72d0 optimize varchar fields in admin/customer table; fixes #752
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-13 08:57:53 +01:00
Michael Kaufmann
e8dcb29b69 keep searching code in ssl_certificates if something was searched and no results were returned, thx to Ithariel
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-12 12:53:38 +01:00
Michael Kaufmann
2b3b68efa3 remove testing code
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-12 08:17:54 +01:00
Michael Kaufmann
d937029bf7 implement [ApiModule].listing() in frontend-module as sorting/limiting/searching is now possible via API call (partly untested)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-10 18:35:32 +01:00
Michael Kaufmann
1955b5dd32 add task to remove certificate from acme.sh when removed in froxlor; fix issue when mode of certificate generation was not reset to 'issue' and kept trying to 'renew' instead
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-10 18:34:02 +01:00
Michael Kaufmann
c2a9880616 add new Api-Module 'SysLog' to query froxlor logs; set default value for api_allowed to the value of api.enabled setting when adding new customer via frontend to behave like Customers.add() API method
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-09 11:37:45 +01:00
Michael Kaufmann
dfedc478f7 check for given customer loginname/id before anything happens in Mysqls.add/update/delete when called as admin; fixes #749
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-07 15:53:30 +01:00
Michael Kaufmann
6efe500cee validate that the admin/reseller has customers in SubDomains.listing(); return all domain fields for admins/resellers in SubDomains.listing()
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-05 11:21:49 +01:00
Michael Kaufmann
9c3549c604 lowercase domain-names in AcmeSh implementation to avoid https://github.com/Neilpang/acme.sh/issues/2556
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-04 11:39:06 +01:00
Michael Kaufmann
50755f4399 set phpunit to fixed 8.4.1 in favor of https://github.com/sebastianbergmann/phpunit/issues/3793 to not break jenkins testing for now
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-02 13:26:38 +01:00
Michael Kaufmann
ef11ad8da7 fix broke count sql-queries
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-02 11:12:49 +01:00
Michael Kaufmann
1b2c186c07 introduce search, limit, offset and orderby possibilities for (almost) all API listing() functions; added listingCount() function in preparation to replace the old UI\Paging class later on
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-02 10:58:52 +01:00
Michael Kaufmann
b162324ff0 fix renew-check of let's encrypt implementation, set version to 0.10.5 for bugfix release; fixes #747
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2019-11-01 14:19:06 +01:00
152 changed files with 12034 additions and 3745 deletions

View File

@@ -1,4 +0,0 @@
codecov:
notify:
require_ci_to_pass: no

View File

@@ -52,13 +52,10 @@ install:
- mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI froxlor010 < install/froxlor.sql
script:
- ant phpunit
after_success:
- bash <(curl -s https://codecov.io/bash) -f "build/logs/clover.xml"
- ant phpunit-no-coverage
notifications:
irc: "irc.freenode.org#froxlor"
irc: "chat.freenode.net#froxlor"
webhooks:
urls:
- https://webhooks.gitter.im/e/bdf91d1c3f745e51f796

View File

@@ -38,7 +38,7 @@ if (AREA == 'admin') {
}
$success_message = "";
$tfa = new \Froxlor\FroxlorTwoFactorAuth('Froxlor');
$tfa = new \Froxlor\FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
// do the delete and then just show a success-message
if ($action == 'delete') {

View File

@@ -53,14 +53,21 @@ https://files.froxlor.org/releases/froxlor-latest.tar.gz [MD5](https://files.fro
[HowTo](https://github.com/Froxlor/Froxlor/wiki/Install-froxlor-on-debian)
/etc/apt/sources.list.d/froxlor.list
> deb http://debian.froxlor.org {stretch|buster} main
```
apt-get -y install apt-transport-https lsb-release ca-certificates
wget -O - https://deb.froxlor.org/froxlor.gpg | apt-key add -
echo "deb https://deb.froxlor.org/debian $(lsb_release -sc) main" > /etc/apt/sources.list.d/froxlor.list
```
### Gentoo repository
### Ubuntu repository
[HowTo](https://github.com/Froxlor/Froxlor/wiki/Install-froxlor-on-gentoo)
[HowTo](https://github.com/Froxlor/Froxlor/wiki/Install-froxlor-on-ubuntu)
https://files.froxlor.org/gentoo/repositories.xml
```
apt-get -y install apt-transport-https lsb-release ca-certificates
wget -O - https://deb.froxlor.org/froxlor.gpg | apt-key add -
echo "deb https://deb.froxlor.org/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/froxlor.list
```
## Contributing

View File

@@ -253,7 +253,23 @@ return array(
'type' => 'hiddenString',
'default' => '',
'save_method' => 'storeSettingField'
)
),
'system_apply_specialsettings_default' => array(
'label' => $lng['serversettings']['apply_specialsettings_default'],
'settinggroup' => 'system',
'varname' => 'apply_specialsettings_default',
'type' => 'bool',
'default' => true,
'save_method' => 'storeSettingField'
),
'system_apply_phpconfigs_default' => array(
'label' => $lng['serversettings']['apply_phpconfigs_default'],
'settinggroup' => 'system',
'varname' => 'apply_phpconfigs_default',
'type' => 'bool',
'default' => true,
'save_method' => 'storeSettingField'
),
)
)
)

View File

@@ -105,6 +105,30 @@ return array(
'hasVhostContainerEnabled'
), true)
),
'system_honorcipherorder' => array(
'label' => $lng['admin']['domain_honorcipherorder'],
'settinggroup' => 'system',
'varname' => 'honorcipherorder',
'type' => 'bool',
'default' => false,
'save_method' => 'storeSettingField',
'visible' => \Froxlor\Settings::Get('system.use_ssl') && call_user_func(array(
'\Froxlor\Settings\FroxlorVhostSettings',
'hasVhostContainerEnabled'
), true)
),
'system_sessiontickets' => array(
'label' => $lng['admin']['domain_sessiontickets'],
'settinggroup' => 'system',
'varname' => 'sessiontickets',
'type' => 'bool',
'default' => true,
'save_method' => 'storeSettingField',
'visible' => \Froxlor\Settings::Get('system.use_ssl') && call_user_func(array(
'\Froxlor\Settings\FroxlorVhostSettings',
'hasVhostContainerEnabled'
), true)
),
/**
* FCGID
*/

View File

@@ -173,7 +173,8 @@ return array(
'websrv_avail' => array(
'apache2',
'nginx'
)
),
'visible' => \Froxlor\Settings::Get('system.awstats_enabled') == 1
),
'system_logfiles_type' => array(
'label' => $lng['serversettings']['logfiles_type'],

View File

@@ -35,7 +35,7 @@ return array(
'settinggroup' => 'system',
'varname' => 'ssl_protocols',
'type' => 'option',
'default' => 'TLSv1,TLSv1.2',
'default' => 'TLSv1.2',
'option_mode' => 'multiple',
'option_options' => array(
'TLSv1' => 'TLSv1',
@@ -62,7 +62,7 @@ return array(
'string_emptyallowed' => true,
'default' => '',
'visible' => \Froxlor\Settings::Get('system.webserver') == "apache2" && \Froxlor\Settings::Get('system.apache24') == 1,
'save_method' => 'storeSettingField',
'save_method' => 'storeSettingField'
),
'system_ssl_cert_file' => array(
'label' => $lng['serversettings']['ssl']['ssl_cert_file'],
@@ -115,6 +115,15 @@ return array(
'visible' => \Froxlor\Settings::Get('system.webserver') == "apache2" && \Froxlor\Settings::Get('system.apache24') == 1,
'save_method' => 'storeSettingField'
),
'system_sessionticketsenabled' => array(
'label' => $lng['admin']['domain_sessionticketsenabled'],
'settinggroup' => 'system',
'varname' => 'sessionticketsenabled',
'type' => 'bool',
'default' => true,
'save_method' => 'storeSettingField',
'visible' => \Froxlor\Settings::Get('system.use_ssl') && (\Froxlor\Settings::Get('system.webserver') == "nginx" || (\Froxlor\Settings::Get('system.webserver') == "apache2" && \Froxlor\Settings::Get('system.apache24') == 1))
),
'system_leenabled' => array(
'label' => $lng['serversettings']['leenabled'],
'settinggroup' => 'system',
@@ -150,10 +159,10 @@ return array(
'settinggroup' => 'system',
'varname' => 'letsencryptca',
'type' => 'option',
'default' => 'testing',
'default' => 'production',
'option_mode' => 'one',
'option_options' => array(
'testing' => 'https://acme-staging' . (\Froxlor\Settings::Get('system.leapiversion') == '2' ? '-v02' : '') . '.api.letsencrypt.org (Test)',
'testing' => 'https://acme-staging-v0' . \Froxlor\Settings::Get('system.leapiversion') . '.api.letsencrypt.org (Test)',
'production' => 'https://acme-v0' . \Froxlor\Settings::Get('system.leapiversion') . '.api.letsencrypt.org (Live)'
),
'save_method' => 'storeSettingField'
@@ -205,11 +214,11 @@ return array(
'save_method' => 'storeSettingField'
),
'system_disable_le_selfcheck' => array(
'label' => $lng['serversettings']['disable_le_selfcheck'],
'label' => $lng['serversettings']['le_domain_dnscheck'],
'settinggroup' => 'system',
'varname' => 'disable_le_selfcheck',
'varname' => 'le_domain_dnscheck',
'type' => 'bool',
'default' => false,
'default' => true,
'save_method' => 'storeSettingField'
)
)

View File

@@ -33,7 +33,8 @@ return array(
1 => $lng['admin']['webalizer']['quiet'],
2 => $lng['admin']['webalizer']['veryquiet']
),
'save_method' => 'storeSettingField'
'save_method' => 'storeSettingField',
'visible' => \Froxlor\Settings::Get('system.awstats_enabled') == 0
),
'system_awstats_enabled' => array(
'label' => $lng['serversettings']['awstats_enabled'],
@@ -50,7 +51,8 @@ return array(
'type' => 'string',
'string_type' => 'dir',
'default' => '/usr/bin/',
'save_method' => 'storeSettingField'
'save_method' => 'storeSettingField',
'visible' => \Froxlor\Settings::Get('system.awstats_enabled') == 1
),
'system_awstats_awstatspath' => array(
'label' => $lng['serversettings']['awstats_awstatspath'],
@@ -59,7 +61,8 @@ return array(
'type' => 'string',
'string_type' => 'dir',
'default' => '/usr/bin/',
'save_method' => 'storeSettingField'
'save_method' => 'storeSettingField',
'visible' => \Froxlor\Settings::Get('system.awstats_enabled') == 1
),
'system_awstats_conf' => array(
'label' => $lng['serversettings']['awstats_conf'],
@@ -68,7 +71,8 @@ return array(
'type' => 'string',
'string_type' => 'dir',
'default' => '/etc/awstats/',
'save_method' => 'storeSettingField'
'save_method' => 'storeSettingField',
'visible' => \Froxlor\Settings::Get('system.awstats_enabled') == 1
),
'system_awstats_icons' => array(
'label' => $lng['serversettings']['awstats_icons'],
@@ -77,7 +81,17 @@ return array(
'type' => 'string',
'string_type' => 'dir',
'default' => '/usr/share/awstats/icon/',
'save_method' => 'storeSettingField'
'save_method' => 'storeSettingField',
'visible' => \Froxlor\Settings::Get('system.awstats_enabled') == 1
),
'system_awstats_logformat' => array(
'label' => $lng['serversettings']['awstats']['logformat'],
'settinggroup' => 'system',
'varname' => 'awstats_logformat',
'type' => 'string',
'default' => '1',
'save_method' => 'storeSettingField',
'visible' => \Froxlor\Settings::Get('system.awstats_enabled') == 1
)
)
)

View File

@@ -43,23 +43,29 @@ if ($page == 'admins' && $userinfo['change_serversettings'] == '1') {
'traffic_used' => $lng['customer']['traffic'] . ' (' . $lng['panel']['used'] . ')',
'deactivated' => $lng['admin']['deactivated']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_ADMINS, $fields);
try {
// get total count
$json_result = Admins::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = Admins::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$admins = '';
$result_stmt = Database::query("SELECT * FROM `" . TABLE_PANEL_ADMINS . "` " . $paging->getSqlWhere(false) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
$numrows_admins = Database::num_rows();
$paging->setEntries($numrows_admins);
$sortcode = $paging->getHtmlSortCode($lng, true);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$i = 0;
$count = 0;
$dec_places = Settings::Get('panel.decimal_places');
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($paging->checkDisplay($i)) {
foreach ($result['list'] as $row) {
$row['traffic_used'] = round($row['traffic_used'] / (1024 * 1024), $dec_places);
$row['traffic'] = round($row['traffic'] / (1024 * 1024), $dec_places);
@@ -100,10 +106,8 @@ if ($page == 'admins' && $userinfo['change_serversettings'] == '1') {
eval("\$admins.=\"" . \Froxlor\UI\Template::getTemplate("admins/admins_admin") . "\";");
$count ++;
}
$i ++;
}
$admincount = $numrows_admins;
$admincount = $paging->getEntries();
eval("echo \"" . \Froxlor\UI\Template::getTemplate("admins/admins") . "\";");
} elseif ($action == 'su') {

View File

@@ -17,8 +17,7 @@
define('AREA', 'admin');
require './lib/init.php';
use Froxlor\Database\Database;
use Froxlor\Api\Commands\Cronjobs as Cronjobs;
use Froxlor\Api\Commands\Cronjobs;
if (isset($_POST['id'])) {
$id = intval($_POST['id']);
@@ -31,47 +30,49 @@ if ($page == 'cronjobs' || $page == 'overview') {
$log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'viewed admin_cronjobs');
$fields = array(
'c.module' => 'Module',
'c.lastrun' => $lng['cron']['lastrun'],
'c.interval' => $lng['cron']['interval'],
'c.isactive' => $lng['cron']['isactive']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_CRONRUNS, $fields);
try {
// get total count
$json_result = Cronjobs::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = Cronjobs::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$crons = '';
$result_stmt = Database::prepare("SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` ORDER BY `module` ASC, `cronfile` ASC");
Database::pexecute($result_stmt);
$paging->setEntries(Database::num_rows());
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$i = 0;
$count = 0;
$cmod = '';
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
foreach ($result['list'] as $row) {
if ($cmod != $row['module']) {
$_mod = explode("/", $row['module']);
$module = ucfirst($_mod[1]);
eval("\$crons.=\"" . \Froxlor\UI\Template::getTemplate('cronjobs/cronjobs_cronjobmodule') . "\";");
$cmod = $row['module'];
}
if ($paging->checkDisplay($i)) {
$row = \Froxlor\PhpHelper::htmlentitiesArray($row);
$row['lastrun'] = date('d.m.Y H:i', $row['lastrun']);
$row['isactive'] = ((int) $row['isactive'] == 1) ? $lng['panel']['yes'] : $lng['panel']['no'];
$description = $lng['crondesc'][$row['desc_lng_key']];
eval("\$crons.=\"" . \Froxlor\UI\Template::getTemplate('cronjobs/cronjobs_cronjob') . "\";");
$count ++;
}
$i ++;
}
eval("echo \"" . \Froxlor\UI\Template::getTemplate('cronjobs/cronjobs') . "\";");
} elseif ($action == 'new') {
/*

View File

@@ -35,6 +35,7 @@ if ($page == 'customers' && $userinfo['customers'] != '0') {
unset($_SESSION['requestData']);
$log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_customers");
$fields = array(
'c.loginname' => $lng['login']['username'],
'a.loginname' => $lng['admin']['admin'],
@@ -47,36 +48,35 @@ if ($page == 'customers' && $userinfo['customers'] != '0') {
'c.traffic' => $lng['customer']['traffic'],
'c.traffic_used' => $lng['customer']['traffic'] . ' (' . $lng['panel']['used'] . ')'
);
try {
// get total count
$json_result = Customers::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = Customers::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_CUSTOMERS, $fields);
$customers = '';
$result_stmt = Database::prepare("
SELECT `c`.*, `a`.`loginname` AS `adminname`
FROM `" . TABLE_PANEL_CUSTOMERS . "` `c`, `" . TABLE_PANEL_ADMINS . "` `a`
WHERE " . ($userinfo['customers_see_all'] ? '' : " `c`.`adminid` = :adminid AND ") . "
`c`.`adminid` = `a`.`adminid` " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
Database::pexecute($result_stmt, array(
'adminid' => $userinfo['adminid']
));
$num_rows = Database::num_rows();
$paging->setEntries($num_rows);
$sortcode = $paging->getHtmlSortCode($lng, true);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$i = 0;
$count = 0;
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($paging->checkDisplay($i)) {
foreach ($result['list'] as $row) {
$domains_stmt = Database::prepare("
SELECT COUNT(`id`) AS `domains`
FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `customerid` = :cid
AND `parentdomainid` = '0'
AND `id`<> :stdd");
AND `id`<> :stdd
");
Database::pexecute($domains_stmt, array(
'cid' => $row['customerid'],
'stdd' => $row['standardsubdomain']
@@ -86,13 +86,16 @@ if ($page == 'customers' && $userinfo['customers'] != '0') {
$dec_places = Settings::Get('panel.decimal_places');
// get disk-space usages for web, mysql and mail
$usages_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DISKSPACE . "` WHERE `customerid` = :cid ORDER BY `stamp` DESC LIMIT 1");
$usages_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_DISKSPACE . "`
WHERE `customerid` = :cid
ORDER BY `stamp` DESC LIMIT 1
");
$usages = Database::pexecute_first($usages_stmt, array(
'cid' => $row['customerid']
));
if ($usages)
{
if ($usages) {
$row['webspace_used'] = round($usages['webspace'] / 1024, $dec_places);
$row['mailspace_used'] = round($usages['mail'] / 1024, $dec_places);
$row['dbspace_used'] = round($usages['mysql'] / 1024, $dec_places);
@@ -110,7 +113,6 @@ if ($page == 'customers' && $userinfo['customers'] != '0') {
/**
* percent-values for progressbar
*/
// For Disk usage
if ($row['diskspace'] > 0) {
$disk_percent = round(($row['diskspace_used'] * 100) / $row['diskspace'], 0);
$disk_doublepercent = round($disk_percent * 2, 2);
@@ -118,7 +120,6 @@ if ($page == 'customers' && $userinfo['customers'] != '0') {
$disk_percent = 0;
$disk_doublepercent = 0;
}
if ($row['traffic'] > 0) {
$traffic_percent = round(($row['traffic_used'] * 100) / $row['traffic'], 0);
$traffic_doublepercent = round($traffic_percent * 2, 2);
@@ -149,10 +150,7 @@ if ($page == 'customers' && $userinfo['customers'] != '0') {
$count ++;
}
$i ++;
}
$customercount = $num_rows;
$customercount = $paging->getEntries();
eval("echo \"" . \Froxlor\UI\Template::getTemplate("customers/customers") . "\";");
} elseif ($action == 'su' && $id != 0) {
try {

View File

@@ -21,6 +21,7 @@ require './lib/init.php';
use Froxlor\Database\Database;
use Froxlor\Settings;
use Froxlor\Api\Commands\Customers as Customers;
use Froxlor\Api\Commands\Domains as Domains;
if (isset($_POST['id'])) {
@@ -31,91 +32,55 @@ if (isset($_POST['id'])) {
if ($page == 'domains' || $page == 'overview') {
// Let's see how many customers we have
$stmt = Database::prepare("
SELECT COUNT(`customerid`) as `countcustomers` FROM `" . TABLE_PANEL_CUSTOMERS . "` " . ($userinfo['customers_see_all'] ? '' : " WHERE `adminid` = :adminid"));
$params = array();
if ($userinfo['customers_see_all'] == '0') {
$params['adminid'] = $userinfo['adminid'];
}
$countcustomers = Database::pexecute_first($stmt, $params);
$countcustomers = (int) $countcustomers['countcustomers'];
$json_result = Customers::getLocal($userinfo)->listingCount();
$countcustomers = json_decode($json_result, true)['data'];
if ($action == '') {
$log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_domains");
$fields = array(
'd.domain' => $lng['domains']['domainname'],
'd.domain_ace' => $lng['domains']['domainname'],
'c.name' => $lng['customer']['name'],
'c.firstname' => $lng['customer']['firstname'],
'c.company' => $lng['customer']['company'],
'c.loginname' => $lng['login']['username'],
'd.aliasdomain' => $lng['domains']['aliasdomain']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_DOMAINS, $fields);
$domains = "";
$result_stmt = Database::prepare("
SELECT `d`.*, `c`.`loginname`, `c`.`deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`, `ad`.`id` AS `aliasdomainid`, `ad`.`domain` AS `aliasdomain`
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `ad` ON `d`.`aliasdomain`=`ad`.`id`
WHERE `d`.`parentdomainid`='0' " . ($userinfo['customers_see_all'] ? '' : " AND `d`.`adminid` = :adminid ") . " " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
$params = array();
if ($userinfo['customers_see_all'] == '0') {
$params['adminid'] = $userinfo['adminid'];
try {
// get total count
$json_result = Domains::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = Domains::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
Database::pexecute($result_stmt, $params);
$numrows_domains = Database::num_rows();
$paging->setEntries($numrows_domains);
$result = json_decode($json_result, true)['data'];
$domains = '';
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$domain_array = array();
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
formatDomainEntry($row, $idna_convert);
if (! isset($domain_array[$row['domain']])) {
$domain_array[$row['domain']] = $row;
} else {
$domain_array[$row['domain']] = array_merge($row, $domain_array[$row['domain']]);
}
if (isset($row['aliasdomainid']) && $row['aliasdomainid'] != null && isset($row['aliasdomain']) && $row['aliasdomain'] != '') {
if (! isset($domain_array[$row['aliasdomain']])) {
$domain_array[$row['aliasdomain']] = array();
}
$domain_array[$row['aliasdomain']]['domainaliasid'] = $row['id'];
$domain_array[$row['aliasdomain']]['domainalias'] = $row['domain'];
}
}
/**
* We need ksort/krsort here to make sure idna-domains are also sorted correctly
*/
if ($paging->sortfield == 'd.domain' && $paging->sortorder == 'asc') {
ksort($domain_array);
} elseif ($paging->sortfield == 'd.domain' && $paging->sortorder == 'desc') {
krsort($domain_array);
}
$i = 0;
$count = 0;
foreach ($domain_array as $row) {
if (isset($row['domain']) && $row['domain'] != '' && $paging->checkDisplay($i)) {
foreach ($result['list'] as $row) {
formatDomainEntry($row, $idna_convert);
$row['customername'] = \Froxlor\User::getCorrectFullUserDetails($row);
$row = \Froxlor\PhpHelper::htmlentitiesArray($row);
// display a nice list of IP's
// display a nice list of IP's if it's not an alias for another domain
if (isset($row['aliasdomainid']) && $row['aliasdomainid'] != null && isset($row['aliasdomain']) && $row['aliasdomain'] != '') {
$row['ipandport'] = sprintf($lng['domains']['isaliasdomainof'], $row['aliasdomain']);
} else {
$row['ipandport'] = str_replace("\n", "<br />", $row['ipandport']);
}
eval("\$domains.=\"" . \Froxlor\UI\Template::getTemplate("domains/domains_domain") . "\";");
$count++;
}
$i ++;
}
$domainscount = $numrows_domains;
$domainscount = $paging->getEntries();
// Display the list
eval("echo \"" . \Froxlor\UI\Template::getTemplate("domains/domains") . "\";");
@@ -416,6 +381,10 @@ if ($page == 'domains' || $page == 'overview') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
// remove ssl ip/ports if set is empty
if (!isset($_POST['ssl_ipandport']) || empty($_POST['ssl_ipandport'])) {
$_POST['remove_ssl_ipandport'] = true;
}
Domains::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
@@ -717,18 +686,8 @@ function formatDomainEntry(&$row, &$idna_convert)
$row['domain'] = $idna_convert->decode($row['domain']);
$row['aliasdomain'] = $idna_convert->decode($row['aliasdomain']);
$resultips_stmt = Database::prepare("
SELECT `ips`.* FROM `" . TABLE_DOMAINTOIP . "` AS `dti`, `" . TABLE_PANEL_IPSANDPORTS . "` AS `ips`
WHERE `dti`.`id_ipandports` = `ips`.`id` AND `dti`.`id_domain` = :domainid
");
Database::pexecute($resultips_stmt, array(
'domainid' => $row['id']
));
$row['ipandport'] = '';
while ($rowip = $resultips_stmt->fetch(PDO::FETCH_ASSOC)) {
foreach ($row['ipsandports'] as $rowip) {
if (filter_var($rowip['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$row['ipandport'] .= '[' . $rowip['ip'] . ']:' . $rowip['port'] . "\n";
} else {

View File

@@ -19,9 +19,8 @@
define('AREA', 'admin');
require './lib/init.php';
use Froxlor\Database\Database;
use Froxlor\Settings;
use Froxlor\Api\Commands\IpsAndPorts as IpsAndPorts;
use Froxlor\Api\Commands\IpsAndPorts;
if (isset($_POST['id'])) {
$id = intval($_POST['id']);
@@ -43,21 +42,27 @@ if ($page == 'ipsandports' || $page == 'overview') {
'ip' => $lng['admin']['ipsandports']['ip'],
'port' => $lng['admin']['ipsandports']['port']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_IPSANDPORTS, $fields);
try {
// get total count
$json_result = IpsAndPorts::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = IpsAndPorts::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$ipsandports = '';
$result_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_IPSANDPORTS . "` " . $paging->getSqlWhere(false) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
Database::pexecute($result_stmt);
$paging->setEntries(Database::num_rows());
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$i = 0;
$count = 0;
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($paging->checkDisplay($i)) {
foreach ($result['list'] as $row) {
$row = \Froxlor\PhpHelper::htmlentitiesArray($row);
if (filter_var($row['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$row['ip'] = '[' . $row['ip'] . ']';
@@ -65,8 +70,6 @@ if ($page == 'ipsandports' || $page == 'overview') {
eval("\$ipsandports.=\"" . \Froxlor\UI\Template::getTemplate("ipsandports/ipsandports_ipandport") . "\";");
$count ++;
}
$i ++;
}
eval("echo \"" . \Froxlor\UI\Template::getTemplate("ipsandports/ipsandports") . "\";");
} elseif ($action == 'delete' && $id != 0) {
try {
@@ -157,5 +160,14 @@ if ($page == 'ipsandports' || $page == 'overview') {
eval("echo \"" . \Froxlor\UI\Template::getTemplate("ipsandports/ipsandports_edit") . "\";");
}
}
} elseif ($action == 'jqCheckIP') {
$ip = $_POST['ip'] ?? "";
if ((filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) || filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE) == false) {
// returns notice if private network detected so we can display it
echo json_encode($lng['admin']['ipsandports']['ipnote']);
} else {
echo 0;
}
exit();
}
}

View File

@@ -19,7 +19,7 @@
define('AREA', 'admin');
require './lib/init.php';
use Froxlor\Database\Database;
use Froxlor\Api\Commands\SysLog;
if ($page == 'log' && $userinfo['change_serversettings'] == '1') {
if ($action == '') {
@@ -29,20 +29,25 @@ if ($page == 'log' && $userinfo['change_serversettings'] == '1') {
'user' => $lng['logger']['user'],
'text' => $lng['logger']['action']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_LOG, $fields, null, null, 0, 'desc', 30);
$query = 'SELECT * FROM `' . TABLE_PANEL_LOG . '` ' . $paging->getSqlWhere(false) . ' ' . $paging->getSqlOrderBy();
$result_stmt = Database::query($query . ' ' . $paging->getSqlLimit());
$result_cnt_stmt = Database::query($query);
$logs_count = $result_cnt_stmt->rowCount();
$paging->setEntries($logs_count);
try {
// get total count
$json_result = SysLog::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = SysLog::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$clog = array();
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
foreach ($result['list'] as $row) {
if (! isset($clog[$row['action']]) || ! is_array($clog[$row['action']])) {
$clog[$row['action']] = array();
}
@@ -55,7 +60,6 @@ if ($page == 'log' && $userinfo['change_serversettings'] == '1') {
ksort($clog);
}
$i = 0;
$count = 0;
$log_count = 0;
$log = '';
@@ -100,23 +104,20 @@ if ($page == 'log' && $userinfo['change_serversettings'] == '1') {
eval("\$log.=\"" . \Froxlor\UI\Template::getTemplate('logger/logger_log') . "\";");
$count ++;
$_action = $action;
// }
$i ++;
}
$i ++;
}
eval("echo \"" . \Froxlor\UI\Template::getTemplate('logger/logger') . "\";");
} elseif ($action == 'truncate') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$truncatedate = time() - (60 * 10);
$trunc_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_LOG . "` WHERE `date` < :trunc");
Database::pexecute($trunc_stmt, array(
'trunc' => $truncatedate
));
$log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, 'truncated the system-log (mysql)');
try {
SysLog::getLocal($userinfo, array(
'min_to_keep' => 10
))->delete();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
\Froxlor\UI\Response::redirectTo($filename, array(
'page' => $page,
's' => $s

View File

@@ -52,7 +52,7 @@ if ($page == 'overview') {
$domains = "";
$subdomains_count = count($row['subdomains']);
foreach ($row['domains'] as $configdomain) {
$domains .= $configdomain . "<br>";
$domains .= $idna_convert->decode($configdomain) . "<br>";
}
$count ++;
if ($subdomains_count == 0 && empty($domains)) {
@@ -81,8 +81,16 @@ if ($page == 'overview') {
));
} else {
if (file_exists(\Froxlor\Froxlor::getInstallDir() . '/templates/misc/php/default.ini.php')) {
require_once \Froxlor\Froxlor::getInstallDir() . '/templates/misc/php/default.ini.php';
$result = [
'phpsettings' => DEFAULT_PHPINI
];
} else {
// use first php-config as fallback
$result_stmt = Database::query("SELECT * FROM `" . TABLE_PANEL_PHPCONFIGS . "` WHERE `id` = 1");
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
}
$fpmconfigs = '';
$configs = Database::query("SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "` ORDER BY `description` ASC");
@@ -90,9 +98,9 @@ if ($page == 'overview') {
$fpmconfigs .= \Froxlor\UI\HTML::makeoption($row['description'], $row['id'], 1, true, true);
}
$pm_select = \Froxlor\UI\HTML::makeoption('static', 'static', 'static', true, true);
$pm_select .= \Froxlor\UI\HTML::makeoption('dynamic', 'dynamic', 'static', true, true);
$pm_select .= \Froxlor\UI\HTML::makeoption('ondemand', 'ondemand', 'static', true, true);
$pm_select = \Froxlor\UI\HTML::makeoption('static', 'static', 'dynamic', true, true);
$pm_select .= \Froxlor\UI\HTML::makeoption('dynamic', 'dynamic', 'dynamic', true, true);
$pm_select .= \Froxlor\UI\HTML::makeoption('ondemand', 'ondemand', 'dynamic', true, true);
$phpconfig_add_data = include_once dirname(__FILE__) . '/lib/formfields/admin/phpconfig/formfield.phpconfig_add.php';
$phpconfig_add_form = \Froxlor\UI\HtmlForm::genHTMLForm($phpconfig_add_data);
@@ -234,9 +242,9 @@ if ($page == 'overview') {
));
} else {
$pm_select = \Froxlor\UI\HTML::makeoption('static', 'static', 'static', true, true);
$pm_select .= \Froxlor\UI\HTML::makeoption('dynamic', 'dynamic', 'static', true, true);
$pm_select .= \Froxlor\UI\HTML::makeoption('ondemand', 'ondemand', 'static', true, true);
$pm_select = \Froxlor\UI\HTML::makeoption('static', 'static', 'dynamic', true, true);
$pm_select .= \Froxlor\UI\HTML::makeoption('dynamic', 'dynamic', 'dynamic', true, true);
$pm_select .= \Froxlor\UI\HTML::makeoption('ondemand', 'ondemand', 'dynamic', true, true);
$fpmconfig_add_data = include_once dirname(__FILE__) . '/lib/formfields/admin/phpconfig/formfield.fpmconfig_add.php';
$fpmconfig_add_form = \Froxlor\UI\HtmlForm::genHTMLForm($fpmconfig_add_data);

View File

@@ -38,34 +38,32 @@ if ($page == '' || $page == 'overview') {
'adminname' => $lng['admin']['admin'],
'p.ts' => $lng['admin']['plans']['last_update']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_PLANS, $fields);
try {
// get total count
$json_result = HostingPlans::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = HostingPlans::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$plans = '';
$result_stmt = Database::prepare("
SELECT p.*, a.loginname as adminname
FROM `" . TABLE_PANEL_PLANS . "` p, `" . TABLE_PANEL_ADMINS . "` a
WHERE " . ($userinfo['customers_see_all'] ? '' : " `p`.`adminid` = :adminid AND ") . "
`p`.`adminid` = `a`.`adminid` " . $paging->getSqlWhere(false) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
Database::pexecute($result_stmt, array(
'adminid' => $userinfo['adminid']
));
$paging->setEntries(Database::num_rows());
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$i = 0;
$count = 0;
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($paging->checkDisplay($i)) {
foreach ($result['list'] as $row) {
$row = \Froxlor\PhpHelper::htmlentitiesArray($row);
$row['ts_format'] = date("d.m.Y H:i", $row['ts']);
eval("\$plans.=\"" . \Froxlor\UI\Template::getTemplate("plans/plans_plan") . "\";");
$count ++;
}
$i ++;
}
eval("echo \"" . \Froxlor\UI\Template::getTemplate("plans/plans") . "\";");
} elseif ($action == 'delete' && $id != 0) {
@@ -191,9 +189,7 @@ if ($page == '' || $page == 'overview') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
HostingPlans::getLocal($userinfo, array(
'id' => $id
))->update();
HostingPlans::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}

View File

@@ -46,10 +46,10 @@
"phpmailer/phpmailer": "~6.0",
"monolog/monolog": "^1.24",
"robthree/twofactorauth": "^1.6",
"algo26-matthias/idna-convert": "^2.1"
"froxlor/idna-convert-legacy": "^2.1"
},
"require-dev": {
"phpunit/phpunit": "^8",
"phpunit/phpunit": "8.4.1",
"php": ">=7.3",
"ext-pcntl": "*",
"phpcompatibility/php-compatibility": "*",

428
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -42,148 +42,67 @@ if ($page == 'overview') {
if ($action == '') {
$log->logAction(\Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_domains::domains");
$fields = array(
'd.domain' => $lng['domains']['domainname']
'd.domain_ace' => $lng['domains']['domainname'],
'd.aliasdomain' => $lng['domains']['aliasdomain']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_DOMAINS, $fields);
$domains_stmt = Database::prepare("SELECT `d`.`id`, `d`.`customerid`, `d`.`domain`, `d`.`documentroot`, `d`.`isbinddomain`, `d`.`isemaildomain`, `d`.`caneditdomain`, `d`.`iswildcarddomain`, `d`.`parentdomainid`, `d`.`letsencrypt`, `d`.`registration_date`, `d`.`termination_date`, `ad`.`id` AS `aliasdomainid`, `ad`.`domain` AS `aliasdomain`, `da`.`id` AS `domainaliasid`, `da`.`domain` AS `domainalias` FROM `" . TABLE_PANEL_DOMAINS . "` `d`
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `ad` ON `d`.`aliasdomain`=`ad`.`id`
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `da` ON `da`.`aliasdomain`=`d`.`id`
WHERE `d`.`customerid`= :customerid
AND `d`.`email_only`='0'
AND `d`.`id` <> :standardsubdomain " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
Database::pexecute($domains_stmt, array(
"customerid" => $userinfo['customerid'],
"standardsubdomain" => $userinfo['standardsubdomain']
));
$paging->setEntries(Database::num_rows());
try {
// get total count
$json_result = SubDomains::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = SubDomains::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$domains = '';
$parentdomains_count = 0;
$domains_count = 0;
$domains_count = $paging->getEntries();
$domain_array = array();
while ($row = $domains_stmt->fetch(PDO::FETCH_ASSOC)) {
$row['domain'] = $idna_convert->decode($row['domain']);
$row['aliasdomain'] = $idna_convert->decode($row['aliasdomain']);
$row['domainalias'] = $idna_convert->decode($row['domainalias']);
foreach ($result['list'] as $row) {
formatDomainEntry($row, $idna_convert);
if ($row['parentdomainid'] == '0' && $row['caneditdomain'] == '1') {
$parentdomains_count ++;
}
/**
* check for set ssl-certs to show different state-icons
*/
// nothing (ssl_global)
$row['domain_hascert'] = 0;
$ssl_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = :domainid");
Database::pexecute($ssl_stmt, array(
"domainid" => $row['id']
));
$ssl_result = $ssl_stmt->fetch(PDO::FETCH_ASSOC);
if (is_array($ssl_result) && isset($ssl_result['ssl_cert_file']) && $ssl_result['ssl_cert_file'] != '') {
// own certificate (ssl_customer_green)
$row['domain_hascert'] = 1;
} else {
// check if it's parent has one set (shared)
if ($row['parentdomainid'] != 0) {
$ssl_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = :domainid");
Database::pexecute($ssl_stmt, array(
"domainid" => $row['parentdomainid']
));
$ssl_result = $ssl_stmt->fetch(PDO::FETCH_ASSOC);
if (is_array($ssl_result) && isset($ssl_result['ssl_cert_file']) && $ssl_result['ssl_cert_file'] != '') {
// parent has a certificate (ssl_shared)
$row['domain_hascert'] = 2;
}
}
$domain_array[$row['parentdomainname']][] = $row;
}
$row['termination_date'] = str_replace("0000-00-00", "", $row['termination_date']);
if ($row['termination_date'] != "") {
$cdate = strtotime($row['termination_date'] . " 23:59:59");
$today = time();
if ($cdate < $today) {
$row['termination_css'] = 'domain-expired';
} else {
$row['termination_css'] = 'domain-canceled';
}
}
$domains_count ++;
$domain_array[$row['domain']] = $row;
}
ksort($domain_array);
$domain_id_array = array();
foreach ($domain_array as $sortkey => $row) {
$domain_id_array[$row['id']] = $sortkey;
}
$domain_sort_array = array();
foreach ($domain_array as $sortkey => $row) {
if ($row['parentdomainid'] == 0) {
$domain_sort_array[$sortkey][$sortkey] = $row;
} else {
// when searching and the results are subdomains only, we need to get
// the parent domain to this subdomain
if (! isset($domain_id_array[$row['parentdomainid']])) {
$domain_id_array[$row['parentdomainid']] = "[parent-domain]";
}
$domain_sort_array[$domain_id_array[$row['parentdomainid']]][$sortkey] = $row;
}
}
$domain_array = array();
if ($paging->sortfield == 'd.domain' && $paging->sortorder == 'asc') {
ksort($domain_sort_array);
} elseif ($paging->sortfield == 'd.domain' && $paging->sortorder == 'desc') {
krsort($domain_sort_array);
}
$i = 0;
foreach ($domain_sort_array as $sortkey => $domain_array) {
if ($paging->checkDisplay($i)) {
if (isset($domain_array[$sortkey])) {
$row = \Froxlor\PhpHelper::htmlentitiesArray($domain_array[$sortkey]);
foreach ($domain_array as $parentdomain => $sdomains) {
// PARENTDOMAIN
if (Settings::Get('system.awstats_enabled') == '1') {
$statsapp = 'awstats';
} else {
$statsapp = 'webalizer';
}
$row = [
'domain' => $idna_convert->decode($parentdomain)
];
eval("\$domains.=\"" . \Froxlor\UI\Template::getTemplate("domains/domains_delimiter") . "\";");
}
if ($paging->sortfield == 'd.domain' && $paging->sortorder == 'asc') {
ksort($domain_array);
} elseif ($paging->sortfield == 'd.domain' && $paging->sortorder == 'desc') {
krsort($domain_array);
}
foreach ($sdomains as $domain) {
$row = \Froxlor\PhpHelper::htmlentitiesArray($domain);
foreach ($domain_array as $row) {
// show docroot nicely
if (strpos($row['documentroot'], $userinfo['documentroot']) === 0) {
$row['documentroot'] = \Froxlor\FileDir::makeCorrectDir(str_replace($userinfo['documentroot'], "/", $row['documentroot']));
}
// get ssl-ips if activated
$show_ssledit = false;
if (Settings::Get('system.use_ssl') == '1' && \Froxlor\Domain\Domain::domainHasSslIpPort($row['id']) && $row['caneditdomain'] == '1' && $row['letsencrypt'] == 0) {
$show_ssledit = true;
}
$row = \Froxlor\PhpHelper::htmlentitiesArray($row);
eval("\$domains.=\"" . \Froxlor\UI\Template::getTemplate("domains/domains_domain") . "\";");
}
}
$i += count($domain_array);
}
eval("echo \"" . \Froxlor\UI\Template::getTemplate("domains/domainlist") . "\";");
} elseif ($action == 'delete' && $id != 0) {
try {
@@ -459,7 +378,9 @@ if ($page == 'overview') {
}
$alias_stmt = Database::prepare("SELECT COUNT(`id`) AS count FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `aliasdomain`= :aliasdomain");
$alias_check = Database::pexecute_first($alias_stmt, array("aliasdomain" => $result['id']));
$alias_check = Database::pexecute_first($alias_stmt, array(
"aliasdomain" => $result['id']
));
$alias_check = $alias_check['count'];
$domainip = $result_ipandport['ip'];
@@ -547,3 +468,53 @@ if ($page == 'overview') {
require_once __DIR__ . '/logfiles_viewer.php';
}
function formatDomainEntry(&$row, &$idna_convert)
{
$row['domain'] = $idna_convert->decode($row['domain']);
$row['aliasdomain'] = $idna_convert->decode($row['aliasdomain']);
$row['domainalias'] = $idna_convert->decode($row['domainalias']);
/**
* check for set ssl-certs to show different state-icons
*/
// nothing (ssl_global)
$row['domain_hascert'] = 0;
$ssl_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = :domainid");
Database::pexecute($ssl_stmt, array(
"domainid" => $row['id']
));
$ssl_result = $ssl_stmt->fetch(PDO::FETCH_ASSOC);
if (is_array($ssl_result) && isset($ssl_result['ssl_cert_file']) && $ssl_result['ssl_cert_file'] != '') {
// own certificate (ssl_customer_green)
$row['domain_hascert'] = 1;
} else {
// check if it's parent has one set (shared)
if ($row['parentdomainid'] != 0) {
$ssl_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = :domainid");
Database::pexecute($ssl_stmt, array(
"domainid" => $row['parentdomainid']
));
$ssl_result = $ssl_stmt->fetch(PDO::FETCH_ASSOC);
if (is_array($ssl_result) && isset($ssl_result['ssl_cert_file']) && $ssl_result['ssl_cert_file'] != '') {
// parent has a certificate (ssl_shared)
$row['domain_hascert'] = 2;
}
}
}
$row['termination_date'] = str_replace("0000-00-00", "", $row['termination_date']);
$row['termination_css'] = "";
if ($row['termination_date'] != "") {
$cdate = strtotime($row['termination_date'] . " 23:59:59");
$today = time();
if ($cdate < $today) {
$row['termination_css'] = 'domain-expired';
} else {
$row['termination_css'] = 'domain-canceled';
}
}
}

View File

@@ -43,27 +43,31 @@ if ($page == 'overview') {
if ($action == '') {
$log->logAction(\Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_email::emails");
$fields = array(
'd.domain' => $lng['domains']['domainname'],
'd.domain_ace' => $lng['domains']['domainname'],
'm.email_full' => $lng['emails']['emailaddress'],
'm.destination' => $lng['emails']['forwarders']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_MAIL_VIRTUAL, $fields);
$result_stmt = Database::prepare('SELECT `m`.`id`, `m`.`domainid`, `m`.`email`, `m`.`email_full`, `m`.`iscatchall`, `u`.`quota`, `m`.`destination`, `m`.`popaccountid`, `d`.`domain`, `u`.`mboxsize` FROM `' . TABLE_MAIL_VIRTUAL . '` `m`
LEFT JOIN `' . TABLE_PANEL_DOMAINS . '` `d` ON (`m`.`domainid` = `d`.`id`)
LEFT JOIN `' . TABLE_MAIL_USERS . '` `u` ON (`m`.`popaccountid` = `u`.`id`)
WHERE `m`.`customerid`= :customerid ' . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
Database::pexecute($result_stmt, array(
"customerid" => $userinfo['customerid']
));
$emailscount = Database::num_rows();
$paging->setEntries($emailscount);
try {
// get total count
$json_result = Emails::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = Emails::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$emails = array();
$emailscount = $paging->getEntries();
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
foreach ($result['list'] as $row) {
if (! isset($emails[$row['domain']]) || ! is_array($emails[$row['domain']])) {
$emails[$row['domain']] = array();
}
@@ -71,13 +75,12 @@ if ($page == 'overview') {
$emails[$row['domain']][$row['email_full']] = $row;
}
if ($paging->sortfield == 'd.domain' && $paging->sortorder == 'desc') {
if ($paging->sortfield == 'd.domain_ace' && $paging->sortorder == 'desc') {
krsort($emails);
} else {
ksort($emails);
}
$i = 0;
$count = 0;
$accounts = '';
$emails_count = 0;
@@ -90,7 +93,6 @@ if ($page == 'overview') {
}
foreach ($emailaddresses as $row) {
if ($paging->checkDisplay($i)) {
if ($domainname != $idna_convert->decode($row['domain'])) {
$domainname = $idna_convert->decode($row['domain']);
eval("\$accounts.=\"" . \Froxlor\UI\Template::getTemplate("email/emails_domain") . "\";");
@@ -124,19 +126,17 @@ if ($page == 'overview') {
eval("\$accounts.=\"" . \Froxlor\UI\Template::getTemplate("email/emails_email") . "\";");
$count ++;
}
$i ++;
}
}
$emaildomains_count_stmt = Database::prepare("SELECT COUNT(`id`) AS `count` FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `customerid`= :customerid
AND `isemaildomain`='1' ORDER BY `domain` ASC");
Database::pexecute($emaildomains_count_stmt, array(
"customerid" => $userinfo['customerid']
$result_stmt = Database::prepare("
SELECT COUNT(`id`) as emaildomains
FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `customerid`= :cid AND `isemaildomain` = '1'
");
$result = Database::pexecute_first($result_stmt, array(
"cid" => $userinfo['customerid']
));
$emaildomains_count = $emaildomains_count_stmt->fetch(PDO::FETCH_ASSOC);
$emaildomains_count = $emaildomains_count['count'];
$emaildomains_count = $result['emaildomains'];
eval("echo \"" . \Froxlor\UI\Template::getTemplate("email/emails") . "\";");
} elseif ($action == 'delete' && $id != 0) {
@@ -194,7 +194,7 @@ if ($page == 'overview') {
$result_stmt = Database::prepare("SELECT `id`, `domain`, `customerid` FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `customerid`= :cid
AND `isemaildomain`='1'
ORDER BY `domain` ASC");
ORDER BY `domain_ace` ASC");
Database::pexecute($result_stmt, array(
"cid" => $userinfo['customerid']
));

View File

@@ -19,7 +19,6 @@
define('AREA', 'customer');
require './lib/init.php';
use Froxlor\Database\Database;
use Froxlor\Settings;
use Froxlor\Api\Commands\DirOptions as DirOptions;
use Froxlor\Api\Commands\DirProtections as DirProtections;
@@ -52,23 +51,27 @@ if ($page == 'overview') {
'username' => $lng['login']['username'],
'path' => $lng['panel']['path']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_HTPASSWDS, $fields);
$result_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_HTPASSWDS . "`
WHERE `customerid`= :customerid " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
Database::pexecute($result_stmt, array(
"customerid" => $userinfo['customerid']
));
$paging->setEntries(Database::num_rows());
try {
// get total count
$json_result = DirProtections::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = DirProtections::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$i = 0;
$count = 0;
$htpasswds = '';
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($paging->checkDisplay($i)) {
foreach ($result['list'] as $row) {
if (strpos($row['path'], $userinfo['documentroot']) === 0) {
$row['path'] = str_replace($userinfo['documentroot'], "/", $row['path']);
}
@@ -78,9 +81,6 @@ if ($page == 'overview') {
$count ++;
}
$i ++;
}
eval("echo \"" . \Froxlor\UI\Template::getTemplate("extras/htpasswds") . "\";");
} elseif ($action == 'delete' && $id != 0) {
try {
@@ -192,25 +192,29 @@ if ($page == 'overview') {
'error500path' => $lng['extras']['error500path'],
'options_cgi' => $lng['extras']['execute_perl']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_HTACCESS, $fields);
$result_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_HTACCESS . "`
WHERE `customerid`= :customerid " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
Database::pexecute($result_stmt, array(
"customerid" => $userinfo['customerid']
));
$paging->setEntries(Database::num_rows());
try {
// get total count
$json_result = DirOptions::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = DirOptions::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$i = 0;
$count = 0;
$htaccess = '';
$cperlenabled = \Froxlor\Customer\Customer::customerHasPerlEnabled($userinfo['customerid']);
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($paging->checkDisplay($i)) {
foreach ($result['list'] as $row) {
if (strpos($row['path'], $userinfo['documentroot']) === 0) {
$row['path'] = str_replace($userinfo['documentroot'], "/", $row['path']);
}
@@ -224,9 +228,6 @@ if ($page == 'overview') {
$count ++;
}
$i ++;
}
eval("echo \"" . \Froxlor\UI\Template::getTemplate("extras/htaccess") . "\";");
} elseif ($action == 'delete' && $id != 0) {
try {

View File

@@ -46,41 +46,38 @@ if ($page == 'overview') {
'homedir' => $lng['panel']['path'],
'description' => $lng['panel']['ftpdesc']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_FTP_USERS, $fields);
$result_stmt = Database::prepare("SELECT `id`, `username`, `description`, `homedir`, `shell` FROM `" . TABLE_FTP_USERS . "`
WHERE `customerid`= :customerid " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
Database::pexecute($result_stmt, array(
"customerid" => $userinfo['customerid']
));
$ftps_count = Database::num_rows();
$paging->setEntries($ftps_count);
try {
// get total count
$json_result = Ftps::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = Ftps::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$ftps_count = $paging->getEntries();
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$i = 0;
$count = 0;
$accounts = '';
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($paging->checkDisplay($i)) {
foreach ($result['list'] as $row) {
if (strpos($row['homedir'], $userinfo['documentroot']) === 0) {
$row['documentroot'] = str_replace($userinfo['documentroot'], "/", $row['homedir']);
} else {
$row['documentroot'] = $row['homedir'];
}
$row['documentroot'] = \Froxlor\FileDir::makeCorrectDir($row['documentroot']);
$row = \Froxlor\PhpHelper::htmlentitiesArray($row);
eval("\$accounts.=\"" . \Froxlor\UI\Template::getTemplate('ftp/accounts_account') . "\";");
$count ++;
}
$i ++;
}
eval("echo \"" . \Froxlor\UI\Template::getTemplate('ftp/accounts') . "\";");
} elseif ($action == 'delete' && $id != 0) {
try {

View File

@@ -19,6 +19,7 @@
define('AREA', 'customer');
require './lib/init.php';
use Froxlor\Api\Commands\SysLog;
use Froxlor\Database\Database;
use Froxlor\Settings;
@@ -35,26 +36,25 @@ if ($page == 'log') {
'user' => $lng['logger']['user'],
'text' => $lng['logger']['action']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_LOG, $fields, null, null, 0, 'desc', 30);
$query = 'SELECT * FROM `' . TABLE_PANEL_LOG . '` WHERE `user` = :loginname ' . $paging->getSqlWhere(true) . ' ' . $paging->getSqlOrderBy();
$result_stmt = Database::prepare($query . ' ' . $paging->getSqlLimit());
Database::pexecute($result_stmt, array(
"loginname" => $userinfo['loginname']
));
$result_cnt_stmt = Database::prepare($query);
Database::pexecute($result_cnt_stmt, array(
"loginname" => $userinfo['loginname']
));
$res_cnt = $result_cnt_stmt->fetch(PDO::FETCH_ASSOC);
$logs_count = $result_cnt_stmt->rowCount();
$paging->setEntries($logs_count);
try {
// get total count
$json_result = SysLog::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = SysLog::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$clog = array();
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
foreach ($result['list'] as $row) {
if (! isset($clog[$row['action']]) || ! is_array($clog[$row['action']])) {
$clog[$row['action']] = array();
@@ -68,7 +68,6 @@ if ($page == 'log') {
ksort($clog);
}
$i = 0;
$count = 0;
$log_count = 0;
$log = '';
@@ -113,10 +112,7 @@ if ($page == 'log') {
eval("\$log.=\"" . \Froxlor\UI\Template::getTemplate('logger/logger_log') . "\";");
$count ++;
$_action = $action;
// }
$i ++;
}
$i ++;
}
eval("echo \"" . \Froxlor\UI\Template::getTemplate('logger/logger') . "\";");

View File

@@ -53,20 +53,24 @@ if ($page == 'overview') {
'databasename' => $lng['mysql']['databasename'],
'description' => $lng['mysql']['databasedescription']
);
$paging = new \Froxlor\UI\Paging($userinfo, TABLE_PANEL_DATABASES, $fields);
$result_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DATABASES . "`
WHERE `customerid`= :customerid " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit());
Database::pexecute($result_stmt, array(
"customerid" => $userinfo['customerid']
));
$mysqls_count = Database::num_rows();
$paging->setEntries($mysqls_count);
try {
// get total count
$json_result = Mysqls::getLocal($userinfo)->listingCount();
$result = json_decode($json_result, true)['data'];
// initialize pagination and filtering
$paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result);
// get list
$json_result = Mysqls::getLocal($userinfo, $paging->getApiCommandParams())->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$mysqls_count = $paging->getEntries();
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
$i = 0;
$count = 0;
$mysqls = '';
@@ -76,8 +80,7 @@ if ($page == 'overview') {
// Begin root-session
Database::needRoot(true);
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($paging->checkDisplay($i)) {
foreach ($result['list'] as $row) {
$row = \Froxlor\PhpHelper::htmlentitiesArray($row);
$mbdata_stmt = Database::prepare("SELECT SUM(data_length + index_length) as MB FROM information_schema.TABLES
WHERE table_schema = :table_schema
@@ -90,8 +93,6 @@ if ($page == 'overview') {
eval("\$mysqls.=\"" . \Froxlor\UI\Template::getTemplate('mysql/mysqls_database') . "\";");
$count ++;
}
$i ++;
}
Database::needRoot(false);
// End root-session

View File

@@ -112,11 +112,14 @@ if (! is_null($month) && ! is_null($year)) {
eval("echo \"" . \Froxlor\UI\Template::getTemplate('traffic/traffic_details') . "\";");
} else {
$result_stmt = Database::prepare("SELECT `month`, `year`, SUM(`http`) AS http, SUM(`ftp_up`) AS ftp_up, SUM(`ftp_down`) AS ftp_down, SUM(`mail`) AS mail
$result_stmt = Database::prepare("
SELECT `month`, `year`, SUM(`http`) AS http, SUM(`ftp_up`) AS ftp_up, SUM(`ftp_down`) AS ftp_down, SUM(`mail`) AS mail
FROM `" . TABLE_PANEL_TRAFFIC . "`
WHERE `customerid` = :customerid
GROUP BY `year` DESC, `month` DESC
LIMIT 12");
GROUP BY `year`, `month`
ORDER BY `year` DESC, `month` DESC
LIMIT 12
");
Database::pexecute($result_stmt, array(
"customerid" => $userinfo['customerid']
));

View File

@@ -37,11 +37,16 @@ $ttl = isset($_POST['record']['ttl']) ? (int) $_POST['record']['ttl'] : 18000;
$domain = \Froxlor\Dns\Dns::getAllowedDomainEntry($domain_id, AREA, $userinfo);
// select all entries
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_DOMAIN_DNS . "` WHERE domain_id = :did");
Database::pexecute($sel_stmt, array(
'did' => $domain_id
));
$dom_entries = $sel_stmt->fetchAll(PDO::FETCH_ASSOC);
try {
// get list
$json_result = DomainZones::getLocal($userinfo, [
'id' => $domain_id
])->listing();
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
$dom_entries = $result['list'];
$errors = "";
$success_message = "";
@@ -117,7 +122,7 @@ $type_select_values = array(
'RP',
'SRV',
'SSHFP',
'TXT',
'TXT'
);
asort($type_select_values);
foreach ($type_select_values as $_type) {

View File

@@ -393,7 +393,7 @@ if ($action == 'forgotpwd') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$loginname = \Froxlor\Validate\Validate::validate($_POST['loginname'], 'loginname');
$email = \Froxlor\Validate\Validate::validateEmail($_POST['loginemail'], 'email');
$result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "`
$result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE `loginname`= :loginname
AND `email`= :email");
Database::pexecute($result_stmt, array(
@@ -481,6 +481,10 @@ if ($action == 'forgotpwd') {
$replace_arr = array(
'SALUTATION' => \Froxlor\User::getCorrectUserSalutation($user),
'NAME' => $user['name'],
'FIRSTNAME' => $user['firstname'] ?? "",
'COMPANY' => $user['company'] ?? "",
'CUSTOMER_NO' => $user['customernumber'] ?? 0,
'USERNAME' => $loginname,
'LINK' => $activationlink
);
@@ -598,21 +602,18 @@ if ($action == 'resetpwd') {
));
if ($result !== false) {
if ($result['admin'] == 1) {
$new_password = \Froxlor\Validate\Validate::validate($_POST['new_password'], 'new password');
$new_password_confirm = \Froxlor\Validate\Validate::validate($_POST['new_password_confirm'], 'new password confirm');
} else {
$new_password = \Froxlor\System\Crypt::validatePassword($_POST['new_password'], 'new password');
$new_password_confirm = \Froxlor\System\Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
try {
$new_password = \Froxlor\System\Crypt::validatePassword($_POST['new_password'], true);
$new_password_confirm = \Froxlor\System\Crypt::validatePassword($_POST['new_password_confirm'], true);
} catch (Exception $e) {
$message = $e->getMessage();
}
if ($new_password == '') {
$message = $new_password;
} elseif ($new_password_confirm == '') {
$message = $new_password_confirm;
} elseif ($new_password != $new_password_confirm) {
$message = $new_password . " != " . $new_password_confirm;
} else {
if (empty($message) && (empty($new_password) || $new_password != $new_password_confirm)) {
$message = $lng['error']['newpasswordconfirmerror'];
}
if (empty($message)) {
// Update user password
if ($result['admin'] == 1) {
$stmt = Database::prepare("UPDATE `" . TABLE_PANEL_ADMINS . "`

View File

@@ -94,7 +94,7 @@ CREATE TABLE `panel_admins` (
`password` varchar(255) NOT NULL default '',
`name` varchar(255) NOT NULL default '',
`email` varchar(255) NOT NULL default '',
`def_language` varchar(255) NOT NULL default '',
`def_language` varchar(100) NOT NULL default '',
`ip` varchar(500) NOT NULL default '-1',
`customers` int(15) NOT NULL default '0',
`customers_used` int(15) NOT NULL default '0',
@@ -127,11 +127,11 @@ CREATE TABLE `panel_admins` (
`lastlogin_fail` int(11) unsigned NOT NULL default '0',
`loginfail_count` int(11) unsigned NOT NULL default '0',
`reportsent` tinyint(4) unsigned NOT NULL default '0',
`theme` varchar(255) NOT NULL default 'Sparkle',
`theme` varchar(50) NOT NULL default 'Sparkle',
`custom_notes` text,
`custom_notes_show` tinyint(1) NOT NULL default '0',
`type_2fa` tinyint(1) NOT NULL default '0',
`data_2fa` varchar(500) NOT NULL default '',
`data_2fa` varchar(25) NOT NULL default '',
`api_allowed` tinyint(1) NOT NULL default '1',
PRIMARY KEY (`adminid`),
UNIQUE KEY `loginname` (`loginname`)
@@ -150,13 +150,13 @@ CREATE TABLE `panel_customers` (
`gender` int(1) NOT NULL DEFAULT '0',
`company` varchar(255) NOT NULL default '',
`street` varchar(255) NOT NULL default '',
`zipcode` varchar(255) NOT NULL default '',
`zipcode` varchar(25) NOT NULL default '',
`city` varchar(255) NOT NULL default '',
`phone` varchar(255) NOT NULL default '',
`fax` varchar(255) NOT NULL default '',
`phone` varchar(50) NOT NULL default '',
`fax` varchar(50) NOT NULL default '',
`email` varchar(255) NOT NULL default '',
`customernumber` varchar(255) NOT NULL default '',
`def_language` varchar(255) NOT NULL default '',
`def_language` varchar(100) NOT NULL default '',
`diskspace` bigint(30) NOT NULL default '0',
`diskspace_used` bigint(30) NOT NULL default '0',
`mysqls` int(15) NOT NULL default '0',
@@ -190,16 +190,15 @@ CREATE TABLE `panel_customers` (
`imap` tinyint(1) NOT NULL default '1',
`perlenabled` tinyint(1) NOT NULL default '0',
`dnsenabled` tinyint(1) NOT NULL default '0',
`theme` varchar(255) NOT NULL default 'Sparkle',
`theme` varchar(50) NOT NULL default 'Sparkle',
`custom_notes` text,
`custom_notes_show` tinyint(1) NOT NULL default '0',
`lepublickey` mediumtext default NULL,
`leprivatekey` mediumtext default NULL,
`leregistered` tinyint(1) NOT NULL default '0',
`leaccount` varchar(255) default '',
`allowed_phpconfigs` varchar(500) NOT NULL default '',
`type_2fa` tinyint(1) NOT NULL default '0',
`data_2fa` varchar(500) NOT NULL default '',
`data_2fa` varchar(25) NOT NULL default '',
`api_allowed` tinyint(1) NOT NULL default '1',
`logviewenabled` tinyint(1) NOT NULL default '0',
PRIMARY KEY (`customerid`),
@@ -225,6 +224,7 @@ DROP TABLE IF EXISTS `panel_domains`;
CREATE TABLE `panel_domains` (
`id` int(11) unsigned NOT NULL auto_increment,
`domain` varchar(255) NOT NULL default '',
`domain_ace` varchar(255) NOT NULL default '',
`adminid` int(11) unsigned NOT NULL default '0',
`customerid` int(11) unsigned NOT NULL default '0',
`aliasdomain` int(11) unsigned NULL,
@@ -272,6 +272,9 @@ CREATE TABLE `panel_domains` (
`ssl_protocols` text,
`ssl_cipher_list` text,
`tlsv13_cipher_list` text,
`ssl_enabled` tinyint(1) DEFAULT '1',
`ssl_honorcipherorder` tinyint(1) DEFAULT '0',
`ssl_sessiontickets` tinyint(1) DEFAULT '1',
PRIMARY KEY (`id`),
KEY `customerid` (`customerid`),
KEY `parentdomain` (`parentdomainid`),
@@ -570,6 +573,7 @@ opcache.interned_strings_buffer'),
('system', 'stdsubdomain', ''),
('system', 'awstats_path', '/usr/bin/'),
('system', 'awstats_conf', '/etc/awstats/'),
('system', 'awstats_logformat', '1'),
('system', 'defaultttl', '604800'),
('system', 'mod_fcgid_defaultini', '1'),
('system', 'ftpserver', 'proftpd'),
@@ -650,9 +654,12 @@ opcache.interned_strings_buffer'),
('system', 'leregistered', '0'),
('system', 'leaccount', ''),
('system', 'nssextrausers', '0'),
('system', 'disable_le_selfcheck', '0'),
('system', 'ssl_protocols', 'TLSv1,TLSv1.2'),
('system', 'le_domain_dnscheck', '1'),
('system', 'ssl_protocols', 'TLSv1.2'),
('system', 'tlsv13_cipher_list', ''),
('system', 'honorcipherorder', '0'),
('system', 'sessiontickets', '1'),
('system', 'sessionticketsenabled', '1'),
('system', 'logfiles_format', ''),
('system', 'logfiles_type', '1'),
('system', 'logfiles_piped', '0'),
@@ -661,6 +668,8 @@ opcache.interned_strings_buffer'),
('system', 'errorlog_level', 'warn'),
('system', 'leecc', '0'),
('system', 'froxloraliases', ''),
('system', 'apply_specialsettings_default', '1'),
('system', 'apply_phpconfigs_default', '1'),
('api', 'enabled', '0'),
('2fa', 'enabled', '1'),
('panel', 'decimal_places', '4'),
@@ -695,8 +704,8 @@ opcache.interned_strings_buffer'),
('panel', 'password_special_char', '!?<>§$%+#=@'),
('panel', 'customer_hide_options', ''),
('panel', 'is_configured', '0'),
('panel', 'version', '0.10.4'),
('panel', 'db_version', '201910200');
('panel', 'version', '0.10.19'),
('panel', 'db_version', '202005150');
DROP TABLE IF EXISTS `panel_tasks`;
@@ -834,14 +843,15 @@ CREATE TABLE `panel_fpmdaemons` (
`description` varchar(50) NOT NULL,
`reload_cmd` varchar(255) NOT NULL,
`config_dir` varchar(255) NOT NULL,
`pm` varchar(15) NOT NULL DEFAULT 'static',
`max_children` int(4) NOT NULL DEFAULT '1',
`start_servers` int(4) NOT NULL DEFAULT '20',
`min_spare_servers` int(4) NOT NULL DEFAULT '5',
`max_spare_servers` int(4) NOT NULL DEFAULT '35',
`pm` varchar(15) NOT NULL DEFAULT 'dynamic',
`max_children` int(4) NOT NULL DEFAULT '5',
`start_servers` int(4) NOT NULL DEFAULT '2',
`min_spare_servers` int(4) NOT NULL DEFAULT '1',
`max_spare_servers` int(4) NOT NULL DEFAULT '3',
`max_requests` int(4) NOT NULL DEFAULT '0',
`idle_timeout` int(4) NOT NULL DEFAULT '30',
`idle_timeout` int(4) NOT NULL DEFAULT '10',
`limit_extensions` varchar(255) NOT NULL default '.php',
`custom_config` text,
PRIMARY KEY (`id`),
UNIQUE KEY `reload` (`reload_cmd`),
UNIQUE KEY `config` (`config_dir`)
@@ -850,7 +860,7 @@ CREATE TABLE `panel_fpmdaemons` (
INSERT INTO `panel_fpmdaemons` (`id`, `description`, `reload_cmd`, `config_dir`) VALUES
(1, 'System default', 'service php7.0-fpm restart', '/etc/php/7.0/fpm/pool.d/');
(1, 'System default', 'service php7.3-fpm restart', '/etc/php/7.3/fpm/pool.d/');
@@ -870,13 +880,13 @@ CREATE TABLE `panel_phpconfigs` (
`fpmsettingid` int(11) NOT NULL DEFAULT '1',
`pass_authorizationheader` tinyint(1) NOT NULL default '0',
`override_fpmconfig` tinyint(1) NOT NULL DEFAULT '0',
`pm` varchar(15) NOT NULL DEFAULT 'static',
`max_children` int(4) NOT NULL DEFAULT '1',
`start_servers` int(4) NOT NULL DEFAULT '20',
`min_spare_servers` int(4) NOT NULL DEFAULT '5',
`max_spare_servers` int(4) NOT NULL DEFAULT '35',
`pm` varchar(15) NOT NULL DEFAULT 'dynamic',
`max_children` int(4) NOT NULL DEFAULT '5',
`start_servers` int(4) NOT NULL DEFAULT '2',
`min_spare_servers` int(4) NOT NULL DEFAULT '1',
`max_spare_servers` int(4) NOT NULL DEFAULT '3',
`max_requests` int(4) NOT NULL DEFAULT '0',
`idle_timeout` int(4) NOT NULL DEFAULT '30',
`idle_timeout` int(4) NOT NULL DEFAULT '10',
`limit_extensions` varchar(255) NOT NULL default '.php',
PRIMARY KEY (`id`),
KEY `fpmsettingid` (`fpmsettingid`)
@@ -885,8 +895,8 @@ CREATE TABLE `panel_phpconfigs` (
INSERT INTO `panel_phpconfigs` (`id`, `description`, `binary`, `file_extensions`, `mod_fcgid_starter`, `mod_fcgid_maxrequests`, `phpsettings`) VALUES
(1, 'Default Config', '/usr/bin/php-cgi', 'php', '-1', '-1', 'allow_call_time_pass_reference = Off\r\nallow_url_fopen = Off\r\nasp_tags = Off\r\ndisable_classes =\r\ndisable_functions = curl_exec,curl_multi_exec,exec,parse_ini_file,passthru,popen,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,shell_exec,show_source,system\r\ndisplay_errors = Off\r\ndisplay_startup_errors = Off\r\nenable_dl = Off\r\nerror_reporting = E_ALL & ~E_NOTICE\r\nexpose_php = Off\r\nfile_uploads = On\r\ncgi.force_redirect = 1\r\ngpc_order = "GPC"\r\nhtml_errors = Off\r\nignore_repeated_errors = Off\r\nignore_repeated_source = Off\r\ninclude_path = ".:{PEAR_DIR}"\r\nlog_errors = On\r\nlog_errors_max_len = 1024\r\nmagic_quotes_gpc = Off\r\nmagic_quotes_runtime = Off\r\nmagic_quotes_sybase = Off\r\nmax_execution_time = 30\r\nmax_input_time = 60\r\nmemory_limit = 128M\r\n{OPEN_BASEDIR_C}open_basedir = "{OPEN_BASEDIR}"\r\noutput_buffering = 4096\r\npost_max_size = 16M\r\nprecision = 14\r\nregister_argc_argv = Off\r\nregister_globals = Off\r\nreport_memleaks = On\r\nsendmail_path = "/usr/sbin/sendmail -t -i -f {CUSTOMER_EMAIL}"\r\nsession.auto_start = 0\r\nsession.bug_compat_42 = 0\r\nsession.bug_compat_warn = 1\r\nsession.cache_expire = 180\r\nsession.cache_limiter = nocache\r\nsession.cookie_domain =\r\nsession.cookie_lifetime = 0\r\nsession.cookie_path = /\r\nsession.entropy_file = /dev/urandom\r\nsession.entropy_length = 16\r\nsession.gc_divisor = 1000\r\nsession.gc_maxlifetime = 1440\r\nsession.gc_probability = 1\r\nsession.name = PHPSESSID\r\nsession.referer_check =\r\nsession.save_handler = files\r\nsession.save_path = "{TMP_DIR}"\r\nsession.serialize_handler = php\r\nsession.use_cookies = 1\r\nsession.use_trans_sid = 0\r\nshort_open_tag = On\r\nsuhosin.mail.protect = 1\r\nsuhosin.simulation = Off\r\ntrack_errors = Off\r\nupload_max_filesize = 32M\r\nupload_tmp_dir = "{TMP_DIR}"\r\nvariables_order = "GPCS"\r\n;mail.add_x_header = On\r\n;mail.log = "/var/log/phpmail.log"\r\nopcache.restrict_api = "{DOCUMENT_ROOT}"\r\n'),
(2, 'Froxlor Vhost Config', '/usr/bin/php-cgi', 'php', '-1', '-1', 'allow_call_time_pass_reference = Off\r\nallow_url_fopen = On\r\nasp_tags = Off\r\ndisable_classes =\r\ndisable_functions = curl_multi_exec,parse_ini_file,passthru,popen,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,shell_exec,show_source,system\r\ndisplay_errors = Off\r\ndisplay_startup_errors = Off\r\nenable_dl = Off\r\nerror_reporting = E_ALL & ~E_NOTICE\r\nexpose_php = Off\r\nfile_uploads = On\r\ncgi.force_redirect = 1\r\ngpc_order = "GPC"\r\nhtml_errors = Off\r\nignore_repeated_errors = Off\r\nignore_repeated_source = Off\r\ninclude_path = ".:{PEAR_DIR}"\r\nlog_errors = On\r\nlog_errors_max_len = 1024\r\nmagic_quotes_gpc = Off\r\nmagic_quotes_runtime = Off\r\nmagic_quotes_sybase = Off\r\nmax_execution_time = 60\r\nmax_input_time = 60\r\nmemory_limit = 128M\r\noutput_buffering = 4096\r\npost_max_size = 16M\r\nprecision = 14\r\nregister_argc_argv = Off\r\nregister_globals = Off\r\nreport_memleaks = On\r\nsendmail_path = "/usr/sbin/sendmail -t -i -f {CUSTOMER_EMAIL}"\r\nsession.auto_start = 0\r\nsession.bug_compat_42 = 0\r\nsession.bug_compat_warn = 1\r\nsession.cache_expire = 180\r\nsession.cache_limiter = nocache\r\nsession.cookie_domain =\r\nsession.cookie_lifetime = 0\r\nsession.cookie_path = /\r\nsession.entropy_file = /dev/urandom\r\nsession.entropy_length = 16\r\nsession.gc_divisor = 1000\r\nsession.gc_maxlifetime = 1440\r\nsession.gc_probability = 1\r\nsession.name = PHPSESSID\r\nsession.referer_check =\r\nsession.save_handler = files\r\nsession.save_path = "{TMP_DIR}"\r\nsession.serialize_handler = php\r\nsession.use_cookies = 1\r\nsession.use_trans_sid = 0\r\nshort_open_tag = On\r\nsuhosin.mail.protect = 1\r\nsuhosin.simulation = Off\r\ntrack_errors = Off\r\nupload_max_filesize = 32M\r\nupload_tmp_dir = "{TMP_DIR}"\r\nvariables_order = "GPCS"\r\n;mail.add_x_header = On\r\n;mail.log = "/var/log/phpmail.log"\r\nopcache.restrict_api = ""\r\n');
(1, 'Default Config', '/usr/bin/php-cgi', 'php', '-1', '-1', 'allow_url_fopen = Off\r\nallow_url_include = Off\r\nauto_append_file =\r\nauto_globals_jit = On\r\nauto_prepend_file =\r\nbcmath.scale = 0\r\ncli_server.color = On\r\ndefault_charset = "UTF-8"\r\ndefault_mimetype = "text/html"\r\ndefault_socket_timeout = 60\r\nasp_tags = Off\r\ndisable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,curl_exec,curl_multi_exec,exec,parse_ini_file,passthru,popen,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,shell_exec,show_source,system\r\ndisplay_errors = Off\r\ndisplay_startup_errors = Off\r\ndoc_root =\r\nenable_dl = Off\r\nerror_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE\r\nexpose_php = Off\r\nfile_uploads = On\r\nhtml_errors = On\r\nignore_repeated_errors = Off\r\nignore_repeated_source = Off\r\ninclude_path = ".:{PEAR_DIR}"\r\nimplicit_flush = Off\r\nldap.max_links = -1\r\nlog_errors = On\r\nlog_errors_max_len = 1024\r\nmail.add_x_header = Off\r\nmax_execution_time = 30\r\nmax_file_uploads = 20\r\nmax_input_time = 60\r\nmemory_limit = 128M\r\n{OPEN_BASEDIR_C}open_basedir = "{OPEN_BASEDIR}"\r\noutput_buffering = 4096\r\npost_max_size = 16M\r\nprecision = 14\r\nregister_argc_argv = Off\r\nreport_memleaks = On\r\nrequest_order = "GP"\r\nsendmail_path = "/usr/sbin/sendmail -t -i -f {CUSTOMER_EMAIL}"\r\nserialize_precision = -1\r\nsession.auto_start = 0\r\nsession.cache_expire = 180\r\nsession.cache_limiter = nocache\r\nsession.cookie_domain =\r\nsession.cookie_httponly =\r\nsession.cookie_lifetime = 0\r\nsession.cookie_path = /\r\nsession.cookie_samesite =\r\nsession.gc_divisor = 1000\r\nsession.gc_maxlifetime = 1440\r\nsession.gc_probability = 0\r\nsession.name = PHPSESSID\r\nsession.referer_check =\r\nsession.save_handler = files\r\nsession.save_path = "{TMP_DIR}"\r\nsession.serialize_handler = php\r\nsession.sid_bits_per_character = 5\r\nsession.sid_length = 26\r\nsession.trans_sid_tags = "a=href,area=href,frame=src,form="\r\nsession.use_cookies = 1\r\nsession.use_only_cookies = 1\r\nsession.use_strict_mode = 0\r\nsession.use_trans_sid = 0\r\nshort_open_tag = On\r\nupload_max_filesize = 32M\r\nupload_tmp_dir = "{TMP_DIR}"\r\nvariables_order = "GPCS"\r\nopcache.restrict_api = "{DOCUMENT_ROOT}"\r\n'),
(2, 'Froxlor Vhost Config', '/usr/bin/php-cgi', 'php', '-1', '-1', 'allow_url_fopen = On\r\nallow_url_include = Off\r\nauto_append_file =\r\nauto_globals_jit = On\r\nauto_prepend_file =\r\nbcmath.scale = 0\r\ncli_server.color = On\r\ndefault_charset = "UTF-8"\r\ndefault_mimetype = "text/html"\r\ndefault_socket_timeout = 60\r\nasp_tags = Off\r\ndisable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,curl_multi_exec,parse_ini_file,passthru,popen,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,shell_exec,show_source,system\r\ndisplay_errors = Off\r\ndisplay_startup_errors = Off\r\ndoc_root =\r\nenable_dl = Off\r\nerror_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE\r\nexpose_php = Off\r\nfile_uploads = On\r\nhtml_errors = On\r\nignore_repeated_errors = Off\r\nignore_repeated_source = Off\r\ninclude_path = ".:{PEAR_DIR}"\r\nimplicit_flush = Off\r\nldap.max_links = -1\r\nlog_errors = On\r\nlog_errors_max_len = 1024\r\nmail.add_x_header = Off\r\nmax_execution_time = 60\r\nmax_file_uploads = 20\r\nmax_input_time = 60\r\nmemory_limit = 128M\r\noutput_buffering = 4096\r\npost_max_size = 16M\r\nprecision = 14\r\nregister_argc_argv = Off\r\nreport_memleaks = On\r\nrequest_order = "GP"\r\nsendmail_path = "/usr/sbin/sendmail -t -i -f {CUSTOMER_EMAIL}"\r\nserialize_precision = -1\r\nsession.auto_start = 0\r\nsession.cache_expire = 180\r\nsession.cache_limiter = nocache\r\nsession.cookie_domain =\r\nsession.cookie_httponly =\r\nsession.cookie_lifetime = 0\r\nsession.cookie_path = /\r\nsession.cookie_samesite =\r\nsession.gc_divisor = 1000\r\nsession.gc_maxlifetime = 1440\r\nsession.gc_probability = 0\r\nsession.name = PHPSESSID\r\nsession.referer_check =\r\nsession.save_handler = files\r\nsession.save_path = "{TMP_DIR}"\r\nsession.serialize_handler = php\r\nsession.sid_bits_per_character = 5\r\nsession.sid_length = 26\r\nsession.trans_sid_tags = "a=href,area=href,frame=src,form="\r\nsession.use_cookies = 1\r\nsession.use_only_cookies = 1\r\nsession.use_strict_mode = 0\r\nsession.use_trans_sid = 0\r\nshort_open_tag = On\r\nupload_max_filesize = 32M\r\nupload_tmp_dir = "{TMP_DIR}"\r\nvariables_order = "GPCS"\r\nopcache.restrict_api = ""\r\n');
DROP TABLE IF EXISTS `cronjobs_run`;
@@ -987,7 +997,8 @@ CREATE TABLE IF NOT EXISTS `domain_ssl_settings` (
`ssl_csr_file` mediumtext,
`ssl_fullchain_file` mediumtext,
`expirationdate` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
PRIMARY KEY (`id`),
UNIQUE KEY (`domainid`)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;

View File

@@ -159,6 +159,7 @@ class FroxlorInstall
$this->_guessServerName();
$this->_guessServerIP();
$this->_guessWebserver();
$this->_guessDistribution();
$this->_getPostField('mysql_host', '127.0.0.1');
$this->_getPostField('mysql_database', 'froxlor');
@@ -332,22 +333,29 @@ class FroxlorInstall
$userdata .= "?>";
// test if we can store the userdata.inc.php in ../lib
$umask = @umask(077);
$userdata_file = dirname(dirname(dirname(__FILE__))) . '/lib/userdata.inc.php';
if ($fp = @fopen($userdata_file, 'w')) {
$result = @fputs($fp, $userdata, strlen($userdata));
if (@touch($userdata_file) && @is_writable($userdata_file)) {
$fp = @fopen($userdata_file, 'w');
@fputs($fp, $userdata, strlen($userdata));
@fclose($fp);
$content .= $this->_status_message('green', 'OK');
chmod($userdata_file, 0440);
} elseif ($fp = @fopen('/tmp/userdata.inc.php', 'w')) {
$result = @fputs($fp, $userdata, strlen($userdata));
} else {
@unlink($userdata_file);
// try creating it in a temporary file
$temp_file = @tempnam(sys_get_temp_dir(), 'fx');
if ($temp_file) {
$fp = @fopen($temp_file, 'w');
@fputs($fp, $userdata, strlen($userdata));
@fclose($fp);
$content .= $this->_status_message('orange', $this->_lng['install']['creating_configfile_temp']);
chmod('/tmp/userdata.inc.php', 0440);
$content .= $this->_status_message('orange', sprintf($this->_lng['install']['creating_configfile_temp'], $temp_file));
} else {
$content .= $this->_status_message('red', $this->_lng['install']['creating_configfile_failed']);
$escpduserdata = nl2br(htmlspecialchars($userdata));
eval("\$content .= \"" . $this->_getTemplate("textarea") . "\";");
}
}
@umask($umask);
return $content;
}
@@ -497,6 +505,17 @@ class FroxlorInstall
$this->_updateSetting($upd_stmt, 'error', 'system', 'errorlog_level');
}
$distros = glob(\Froxlor\FileDir::makeCorrectDir(\Froxlor\Froxlor::getInstallDir() . '/lib/configfiles/') . '*.xml');
foreach ($distros as $_distribution) {
if($this->_data['distribution'] == str_replace(".xml", "", strtolower(basename($_distribution)))) {
$dist = new \Froxlor\Config\ConfigParser($_distribution);
$defaults = $dist->getDefaults();
foreach ($defaults->property as $property) {
$this->_updateSetting($upd_stmt, $property->value, $property->settinggroup, $property->varname);
}
}
}
$this->_updateSetting($upd_stmt, $this->_data['activate_newsfeed'], 'admin', 'show_news_feed');
$this->_updateSetting($upd_stmt, dirname(dirname(dirname(__FILE__))), 'system', 'letsencryptchallengepath');
@@ -563,7 +582,7 @@ class FroxlorInstall
for ($i = 0; $i < sizeof($sql_query); $i ++) {
if (trim($sql_query[$i]) != '') {
try {
$result = $db->query($sql_query[$i]);
$db->query($sql_query[$i]);
} catch (\PDOException $e) {
$content .= $this->_status_message('red', $e->getMessage());
$fatal_fail = true;
@@ -730,7 +749,7 @@ class FroxlorInstall
}
if ($do_backup) {
$command = $mysql_dump . " " . $this->_data['mysql_database'] . " -u " . $this->_data['mysql_root_user'] . " --password='" . $this->_data['mysql_root_pass'] . "' --result-file=" . $filename;
$command = $mysql_dump . " " . escapeshellarg($this->_data['mysql_database']) . " -u " . escapeshellarg($this->_data['mysql_root_user']) . " --password='" . escapeshellarg($this->_data['mysql_root_pass']) . "' --result-file=" . $filename;
$output = exec($command);
if (stristr($output, "error")) {
$content .= $this->_status_message('red', $this->_lng['install']['backup_failed']);
@@ -833,6 +852,32 @@ class FroxlorInstall
*/
$section = $this->_lng['install']['serversettings'];
eval("\$formdata .= \"" . $this->_getTemplate("datasection") . "\";");
// distribution
if (! empty($_POST['installstep']) && $this->_data['distribution'] == '') {
$diststyle = 'color:red;';
} else {
$diststyle = '';
}
// show list of available distro's
$distros = glob(\Froxlor\FileDir::makeCorrectDir(\Froxlor\Froxlor::getInstallDir() . '/lib/configfiles/') . '*.xml');
foreach ($distros as $_distribution) {
$dist = new \Froxlor\Config\ConfigParser($_distribution);
$dist_display = $dist->distributionName." ".$dist->distributionCodename." (" . $dist->distributionVersion . ")";
$distributions_select_data[$dist_display] .= str_replace(".xml", "", strtolower(basename($_distribution)));
}
// sort by distribution name
ksort($distributions_select_data);
foreach ($distributions_select_data as $dist_display => $dist_index) {
// create select-box-option
$distributions_select .= \Froxlor\UI\HTML::makeoption($dist_display, $dist_index, $this->_data['distribution']);
//$this->_data['distribution']
}
$formdata .= $this->_getSectionItemSelectbox('distribution', $distributions_select, $diststyle);
// servername
if (! empty($_POST['installstep']) && $this->_data['servername'] == '') {
$style = 'color:red;';
@@ -854,12 +899,12 @@ class FroxlorInstall
$websrvstyle = '';
}
// apache
$formdata .= $this->_getSectionItemCheckbox('apache2', ($this->_data['webserver'] == 'apache2'), $websrvstyle);
$formdata .= $this->_getSectionItemCheckbox('apache24', ($this->_data['webserver'] == 'apache24'), $websrvstyle);
$formdata .= $this->_getSectionItemCheckbox('webserver', 'apache2', ($this->_data['webserver'] == 'apache2'), $websrvstyle);
$formdata .= $this->_getSectionItemCheckbox('webserver', 'apache24', ($this->_data['webserver'] == 'apache24'), $websrvstyle);
// lighttpd
$formdata .= $this->_getSectionItemCheckbox('lighttpd', ($this->_data['webserver'] == 'lighttpd'), $websrvstyle);
$formdata .= $this->_getSectionItemCheckbox('webserver', 'lighttpd', ($this->_data['webserver'] == 'lighttpd'), $websrvstyle);
// nginx
$formdata .= $this->_getSectionItemCheckbox('nginx', ($this->_data['webserver'] == 'nginx'), $websrvstyle);
$formdata .= $this->_getSectionItemCheckbox('webserver', 'nginx', ($this->_data['webserver'] == 'nginx'), $websrvstyle);
// webserver-user
if (! empty($_POST['installstep']) && $this->_data['httpuser'] == '') {
$style = 'color:red;';
@@ -911,7 +956,7 @@ class FroxlorInstall
}
/**
* generate form radio field for webserver-selection
* generate form radio field
*
* @param string $fieldname
* @param boolean $checked
@@ -919,8 +964,9 @@ class FroxlorInstall
*
* @return string
*/
private function _getSectionItemCheckbox($fieldname = null, $checked = false, $style = "")
private function _getSectionItemCheckbox($groupname = null, $fieldname = null, $checked = false, $style = "")
{
$groupname = $this->_lng['install'][$groupname];
$fieldlabel = $this->_lng['install'][$fieldname];
if ($checked) {
$checked = 'checked="checked"';
@@ -930,6 +976,25 @@ class FroxlorInstall
return $sectionitem;
}
/**
* generate form selectbox
*
* @param string $fieldname
* @param boolean $options
* @param string $style
*
* @return string
*/
private function _getSectionItemSelectbox($fieldname = null, $options = null, $style = "")
{
$groupname = $this->_lng['install'][$groupname];
$fieldlabel = $this->_lng['install'][$fieldname];
$sectionitem = "";
eval("\$sectionitem .= \"" . $this->_getTemplate("dataitemselect") . "\";");
return $sectionitem;
}
/**
* generate form checkbox field
*
@@ -1266,6 +1331,39 @@ class FroxlorInstall
}
}
/**
* get/guess linux distribution
*/
private function _guessDistribution()
{
// post
if (! empty($_POST['distribution'])) {
$this->_data['distribution'] = $_POST['distribution'];
} else {
//set default os.
$os_dist = array('ID' => 'buster');
$os_version = array('0' => '10');
//read os-release
if(file_exists('/etc/os-release')) {
$os_dist = parse_ini_file('/etc/os-release', false);
if(is_array($os_dist) && array_key_exists('ID', $os_dist) && array_key_exists('VERSION_ID', $os_dist)) {
$os_version = explode('.',$os_dist['VERSION_ID'])[0];
}
}
$distros = glob(\Froxlor\FileDir::makeCorrectDir(\Froxlor\Froxlor::getInstallDir() . '/lib/configfiles/') . '*.xml');
foreach ($distros as $_distribution) {
$dist = new \Froxlor\Config\ConfigParser($_distribution);
$ver = explode('.', $dist->distributionVersion)[0];
if (strtolower($os_dist['ID']) == strtolower($dist->distributionName) && $os_version == $ver) {
$this->_data['distribution'] = str_replace(".xml", "", strtolower(basename($_distribution)));
}
}
}
}
/**
* check if POST field is set and get value for the
* internal data array, if not set use either '' or $default if != null

View File

@@ -63,6 +63,7 @@ $lng['install']['admin_pass1'] = 'Administrator Password';
$lng['install']['admin_pass2'] = 'Administrator-Password (confirm)';
$lng['install']['activate_newsfeed'] = 'Enable the official newsfeed<br><small>(https://inside.froxlor.org/news/)</small>';
$lng['install']['serversettings'] = 'Server settings';
$lng['install']['distribution'] = 'Distribution';
$lng['install']['servername'] = 'Server name (FQDN, no ip-address)';
$lng['install']['serverip'] = 'Server IP';
$lng['install']['webserver'] = 'Webserver';
@@ -86,7 +87,7 @@ $lng['install']['changing_data'] = 'Adjusting settings...';
$lng['install']['creating_entries'] = 'Inserting new values...';
$lng['install']['adding_admin_user'] = 'Creating admin-account...';
$lng['install']['creating_configfile'] = 'Creating configfile...';
$lng['install']['creating_configfile_temp'] = 'File was saved in /tmp/userdata.inc.php, please move to ' . dirname(dirname(__DIR__)) . '/lib/.';
$lng['install']['creating_configfile_temp'] = 'File was saved in %s, please move to ' . dirname(dirname(__DIR__)) . '/lib/userdata.inc.php';
$lng['install']['creating_configfile_failed'] = 'Could not create ' . dirname(dirname(__DIR__)) . '/lib/userdata.inc.php, please create it manually with the following content:';
$lng['install']['froxlor_succ_installed'] = 'Froxlor was installed successfully.';

View File

@@ -53,6 +53,7 @@ $lng['install']['admin_user'] = 'Nom d\'utilisateur administrateur';
$lng['install']['admin_pass1'] = 'Mot de passe administrateur';
$lng['install']['admin_pass2'] = 'Mot de passe administrateur (confirmez)';
$lng['install']['serversettings'] = 'Réglages serveur';
$lng['install']['distribution'] = 'Distribution';
$lng['install']['servername'] = 'Nom du serveur (FQDN, pas d\'adresse IP)';
$lng['install']['serverip'] = 'Adresse IP du serveur';
$lng['install']['webserver'] = 'Serveur Web';
@@ -76,7 +77,7 @@ $lng['install']['changing_data'] = 'Ajustement des paramètres...';
$lng['install']['creating_entries'] = 'Insertion des nouvelles valeurs...';
$lng['install']['adding_admin_user'] = 'Création du compte administrateur...';
$lng['install']['creating_configfile'] = 'Création du fichier de configuration...';
$lng['install']['creating_configfile_temp'] = 'Le fichier a été enregistré dans /tmp/userdata.inc.php, merci de le déplacer dans ' . dirname(dirname(__DIR__)) . '/lib/.';
$lng['install']['creating_configfile_temp'] = 'Le fichier a été enregistré dans %s, merci de le déplacer dans ' . dirname(dirname(__DIR__)) . '/lib/userdata.inc.php';
$lng['install']['creating_configfile_failed'] = 'Impossible de créer ' . dirname(dirname(__DIR__)) . '/lib/userdata.inc.php, merci de le créer manuellement avec le contenu suivant:';
$lng['install']['froxlor_succ_installed'] = 'Froxlor a été installé avec succès.';

View File

@@ -63,6 +63,7 @@ $lng['install']['admin_pass1'] = 'Administrator-Passwort';
$lng['install']['admin_pass2'] = 'Administrator-Passwort (Bestätigung)';
$lng['install']['activate_newsfeed'] = 'Aktiviere das offizielle Newsfeed<br><small>(https://inside.froxlor.org/news/)</small>';
$lng['install']['serversettings'] = 'Servereinstellungen';
$lng['install']['distribution'] = 'Distribution';
$lng['install']['servername'] = 'Servername (FQDN, keine IP-Adresse)';
$lng['install']['serverip'] = 'Server-IP';
$lng['install']['webserver'] = 'Webserver';
@@ -86,7 +87,7 @@ $lng['install']['changing_data'] = 'Einstellungen anpassen...';
$lng['install']['creating_entries'] = 'Trage neue Werte ein...';
$lng['install']['adding_admin_user'] = 'Erstelle Admin-Benutzer...';
$lng['install']['creating_configfile'] = 'Erstelle Konfigurationsdatei...';
$lng['install']['creating_configfile_temp'] = 'Datei wurde in /tmp/userdata.inc.php gespeichert, bitte nach ' . dirname(dirname(__DIR__)) . '/lib/ verschieben.';
$lng['install']['creating_configfile_temp'] = 'Datei wurde in %s gespeichert, bitte nach ' . dirname(dirname(__DIR__)) . '/lib/userdata.inc.php verschieben.';
$lng['install']['creating_configfile_failed'] = 'Konnte ' . dirname(dirname(__DIR__)) . '/lib/userdata.inc.php nicht erstellen, bitte manuell mit folgendem Inhalt anlegen:';
$lng['install']['froxlor_succ_installed'] = 'Froxlor wurde erfolgreich installiert.';

View File

@@ -1,4 +1,4 @@
<p>
<label for="{$fieldname}" class="install-block {$style}">{$this->_lng['install']['webserver']} {$fieldlabel}:</label>
<input type="radio" name="webserver" id="{$fieldname}" value="{$fieldname}" {$checked} /><span>{$fieldlabel}</span>
<label for="{$fieldname}" class="install-block {$style}">{$groupname} {$fieldlabel}:</label>
<input type="radio" name="{$groupname}" id="{$fieldname}" value="{$fieldname}" {$checked} /><span>{$fieldlabel}</span>
</p>

View File

@@ -0,0 +1,6 @@
<p>
<label for="{$fieldname}" class="install-block {$style}">{$fieldlabel}:</label>
<select name="{$fieldname}" id="{$fieldname}" class="dropdown">
{$options}
</select>
</p>

View File

@@ -452,3 +452,200 @@ if (\Froxlor\Froxlor::isFroxlorVersion('0.10.3')) {
showUpdateStep("Updating from 0.10.3 to 0.10.4", false);
\Froxlor\Froxlor::updateToVersion('0.10.4');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.4')) {
showUpdateStep("Updating from 0.10.4 to 0.10.5", false);
\Froxlor\Froxlor::updateToVersion('0.10.5');
}
if (\Froxlor\Froxlor::isDatabaseVersion('201910200')) {
showUpdateStep("Optimizing customer and admin table for size");
// ALTER TABLE `panel_customers` CHANGE `name` `name` VARCHAR(250) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '';
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE `zipcode` `zipcode` varchar(25) NOT NULL default '';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE `phone` `phone` varchar(50) NOT NULL default '';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE `fax` `fax` varchar(50) NOT NULL default '';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE `def_language` `def_language` varchar(100) NOT NULL default '';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE `theme` `theme` varchar(50) NOT NULL default 'Sparkle';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE `data_2fa` `data_2fa` varchar(25) NOT NULL default '';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE `def_language` `def_language` varchar(100) NOT NULL default '';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` DROP `leaccount`;");
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` CHANGE `def_language` `def_language` varchar(100) NOT NULL default '';");
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` CHANGE `theme` `theme` varchar(50) NOT NULL default 'Sparkle';");
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` CHANGE `data_2fa` `data_2fa` varchar(25) NOT NULL default '';");
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('201911130');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.5')) {
showUpdateStep("Updating from 0.10.5 to 0.10.6", false);
\Froxlor\Froxlor::updateToVersion('0.10.6');
}
if (\Froxlor\Froxlor::isDatabaseVersion('201911130')) {
showUpdateStep("Adding new settings for domain edit form default values");
Settings::AddNew("system.apply_specialsettings_default", '1');
Settings::AddNew("system.apply_phpconfigs_default", '1');
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('201911220');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.6')) {
showUpdateStep("Updating from 0.10.6 to 0.10.7", false);
\Froxlor\Froxlor::updateToVersion('0.10.7');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.7')) {
showUpdateStep("Updating from 0.10.7 to 0.10.8", false);
\Froxlor\Froxlor::updateToVersion('0.10.8');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.8')) {
showUpdateStep("Updating from 0.10.8 to 0.10.9", false);
\Froxlor\Froxlor::updateToVersion('0.10.9');
}
if (\Froxlor\Froxlor::isDatabaseVersion('201911220')) {
showUpdateStep("Adding enhanced SSL control over domains");
// customer domains
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `ssl_enabled` tinyint(1) DEFAULT '1';");
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `ssl_honorcipherorder` tinyint(1) DEFAULT '0' AFTER `ssl_enabled`;");
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `ssl_sessiontickets` tinyint(1) DEFAULT '1' AFTER `ssl_honorcipherorder`;");
// as setting for froxlor vhost
Settings::AddNew("system.honorcipherorder", '0');
Settings::AddNew("system.sessiontickets", '1');
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('201912100');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.9')) {
showUpdateStep("Updating from 0.10.9 to 0.10.10", false);
\Froxlor\Froxlor::updateToVersion('0.10.10');
}
if (\Froxlor\Froxlor::isDatabaseVersion('201912100')) {
showUpdateStep("Adding option to disable SSL sessiontickets for older systems");
Settings::AddNew("system.sessionticketsenabled", '1');
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('201912310');
}
if (\Froxlor\Froxlor::isDatabaseVersion('201912310')) {
showUpdateStep("Adding custom phpfpm pool configuration field");
Database::query("ALTER TABLE `" . TABLE_PANEL_FPMDAEMONS . "` ADD `custom_config` text AFTER `limit_extensions`;");
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('201912311');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.10')) {
showUpdateStep("Updating from 0.10.10 to 0.10.11", false);
\Froxlor\Froxlor::updateToVersion('0.10.11');
}
if (\Froxlor\Froxlor::isDatabaseVersion('201912311')) {
showUpdateStep("Migrate logfiles_format setting");
$current_format = Settings::Set('system.logfiles_format');
if (! empty($current_format)) {
Settings::Set('system.logfiles_format', '"' . Settings::Get('system.logfiles_format') . '"');
lastStepStatus(0);
} else {
lastStepStatus(0, 'not needed');
}
\Froxlor\Froxlor::updateToDbVersion('201912312');
}
if (\Froxlor\Froxlor::isDatabaseVersion('201912312')) {
showUpdateStep("Adding option change awstats LogFormat");
Settings::AddNew("system.awstats_logformat", '1');
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('201912313');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.11')) {
showUpdateStep("Updating from 0.10.11 to 0.10.12", false);
\Froxlor\Froxlor::updateToVersion('0.10.12');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.12')) {
showUpdateStep("Updating from 0.10.12 to 0.10.13", false);
\Froxlor\Froxlor::updateToVersion('0.10.13');
}
if (\Froxlor\Froxlor::isDatabaseVersion('201912313')) {
showUpdateStep("Adding new field to domains table");
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `domain_ace` varchar(255) NOT NULL default '' AFTER `domain`;");
lastStepStatus(0);
showUpdateStep("Updating domain entries");
$upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `domain_ace` = :ace WHERE `id` = :domainid");
$sel_stmt = Database::prepare("SELECT id, domain FROM `" . TABLE_PANEL_DOMAINS . "` ORDER BY id ASC");
Database::pexecute($sel_stmt);
$idna_convert = new \Froxlor\Idna\IdnaWrapper();
while ($domain = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
Database::pexecute($upd_stmt, [
'ace' => $idna_convert->decode($domain['domain']),
'domainid' => $domain['id']
]);
}
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('202002290');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.13')) {
showUpdateStep("Updating from 0.10.13 to 0.10.14", false);
\Froxlor\Froxlor::updateToVersion('0.10.14');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.14')) {
showUpdateStep("Updating from 0.10.14 to 0.10.15", false);
\Froxlor\Froxlor::updateToVersion('0.10.15');
}
if (\Froxlor\Froxlor::isDatabaseVersion('202002290')) {
showUpdateStep("Adding new setting to validate DNS when using Let's Encrypt");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'system' AND `varname` = 'disable_le_selfcheck'");
$le_domain_dnscheck = isset($_POST['system_le_domain_dnscheck']) ? (int) $_POST['system_le_domain_dnscheck'] : '1';
Settings::AddNew("system.le_domain_dnscheck", $le_domain_dnscheck);
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('202004140');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.15')) {
showUpdateStep("Updating from 0.10.15 to 0.10.16", false);
\Froxlor\Froxlor::updateToVersion('0.10.16');
}
if (\Froxlor\Froxlor::isDatabaseVersion('202004140')) {
showUpdateStep("Adding unique key on domainid field in domain ssl table");
// check for duplicate entries prior to set a unique key to avoid errors on update
Database::query("
DELETE a.* FROM domain_ssl_settings AS a
LEFT JOIN domain_ssl_settings AS b ON
((b.`domainid`=a.`domainid` AND UNIX_TIMESTAMP(b.`expirationdate`) > UNIX_TIMESTAMP(a.`expirationdate`))
OR (UNIX_TIMESTAMP(b.`expirationdate`) = UNIX_TIMESTAMP(a.`expirationdate`) AND b.`id`>a.`id`))
WHERE b.`id` IS NOT NULL
");
Database::query("ALTER TABLE `domain_ssl_settings` ADD UNIQUE(`domainid`)");
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('202005150');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.16')) {
showUpdateStep("Updating from 0.10.16 to 0.10.17", false);
\Froxlor\Froxlor::updateToVersion('0.10.17');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.17')) {
showUpdateStep("Updating from 0.10.17 to 0.10.18", false);
\Froxlor\Froxlor::updateToVersion('0.10.18');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.18')) {
showUpdateStep("Updating from 0.10.18 to 0.10.19", false);
\Froxlor\Froxlor::updateToVersion('0.10.19');
}

View File

@@ -34,6 +34,9 @@ function getPreConfig($current_version, $current_db_version)
include_once \Froxlor\FileDir::makeCorrectFile(dirname(__FILE__) . '/preconfig/0.9/preconfig_0.9.inc.php');
parseAndOutputPreconfig($has_preconfig, $return, $current_version, $current_db_version);
include_once \Froxlor\FileDir::makeCorrectFile(dirname(__FILE__) . '/preconfig/0.10/preconfig_0.10.inc.php');
parseAndOutputPreconfig2($has_preconfig, $return, $current_version, $current_db_version);
$return .= '<br /><br />' . \Froxlor\UI\HTML::makecheckbox('update_changesagreed', '<strong>I have read the update notifications above and I am aware of the changes made to my system.</strong>', '1', true, '0', true);
$return .= '</div>';
$return .= '<input type="hidden" name="update_preconfig" value="1" />';

View File

@@ -0,0 +1,42 @@
<?php
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* For the full copyright and license information, please view the COPYING
* file that was distributed with this source code. You can also view the
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
*
* @copyright (c) the authors
* @author Froxlor team <team@froxlor.org> (2010-)
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
* @package Updater
*
*/
/**
* checks if the new-version has some updating to do
*
* @param boolean $has_preconfig
* pointer to check if any preconfig has to be output
* @param string $return
* pointer to output string
* @param string $current_version
* current froxlor version
*
* @return null
*/
function parseAndOutputPreconfig2(&$has_preconfig, &$return, $current_version, $current_db_version)
{
global $lng;
if (versionInUpdate($current_db_version, '202004140')) {
$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).<br />';
$question = '<strong>Validate DNS of domains when using Lets Encrypt&nbsp;';
$question .= \Froxlor\UI\HTML::makeyesno('system_le_domain_dnscheck', '1', '0', '1');
eval("\$return.=\"" . \Froxlor\UI\Template::getTemplate("update/preconfigitem") . "\";");
}
}

View File

@@ -600,8 +600,8 @@ function parseAndOutputPreconfig(&$has_preconfig, &$return, $current_version, $c
if (versionInUpdate($current_version, '0.9.32-rc2')) {
$has_preconfig = true;
$description = 'To customize the command which executes the cronjob (php - basically) change the path below according to your system.<br /><br />';
$question = '<strong>Please specify the command to execute cronscripts</strong> (default: "/usr/bin/nice -n 5 /usr/bin/php5 -q")<br />';
$question .= '<input type="text" class="text" name="croncmdline" value="/usr/bin/nice -n 5 /usr/bin/php5 -q" /><br />';
$question = '<strong>Please specify the command to execute cronscripts</strong> (default: "/usr/bin/nice -n 5 /usr/bin/php -q")<br />';
$question .= '<input type="text" class="text" name="croncmdline" value="/usr/bin/nice -n 5 /usr/bin/php -q" /><br />';
eval("\$return.=\"" . \Froxlor\UI\Template::getTemplate("update/preconfigitem") . "\";");
}

View File

@@ -54,6 +54,13 @@ abstract class ApiCommand extends ApiParameter
*/
private $mail = null;
/**
* whether the call is an internal one or not
*
* @var boolean
*/
private $internal_call = false;
/**
* language strings array
*
@@ -90,10 +97,12 @@ abstract class ApiCommand extends ApiParameter
* optional, array of parameters (var=>value) for the command
* @param array $userinfo
* optional, passed via WebInterface (instead of $header)
* @param boolean $internal
* optional whether called internally, default false
*
* @throws \Exception
*/
public function __construct($header = null, $params = null, $userinfo = null)
public function __construct($header = null, $params = null, $userinfo = null, $internal = false)
{
parent::__construct($params);
@@ -127,6 +136,9 @@ abstract class ApiCommand extends ApiParameter
if ($this->debug) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::LOG_ERROR, LOG_DEBUG, "[API] " . get_called_class() . ": " . json_encode($params, JSON_UNESCAPED_SLASHES));
}
// set internal call flag
$this->internal_call = $internal;
}
/**
@@ -191,13 +203,15 @@ abstract class ApiCommand extends ApiParameter
* array of user-data
* @param array $params
* array of parameters for the command
* @param boolean $internal
* optional whether called internally, default false
*
* @return ApiCommand
* @throws \Exception
*/
public static function getLocal($userinfo = null, $params = null)
public static function getLocal($userinfo = null, $params = null, $internal = false)
{
return new static(null, $params, $userinfo);
return new static(null, $params, $userinfo, $internal);
}
/**
@@ -210,6 +224,16 @@ abstract class ApiCommand extends ApiParameter
return $this->is_admin;
}
/**
* internal call flag
*
* @return boolean
*/
protected function isInternal()
{
return $this->internal_call;
}
/**
* return field from user-table
*
@@ -232,6 +256,166 @@ abstract class ApiCommand extends ApiParameter
return $this->user_data;
}
/**
* return SQL when parameter $sql_search is given via API
*
* @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 array $query_fields
* optional array of placeholders mapped to the actual value which is used in the API commands when executing the statement [internal]
* @param boolean $append
* optional append to WHERE clause rather then create new one, default false [internal]
*
* @return string
*/
protected function getSearchWhere(&$query_fields = array(), $append = false)
{
$search = $this->getParam('sql_search', true, array());
$condition = '';
if (! empty($search)) {
if ($append == true) {
$condition = ' AND ';
} else {
$condition = ' WHERE ';
}
$ops = array(
'<',
'>',
'='
);
$first = true;
foreach ($search as $field => $valoper) {
$cleanfield = str_replace(".", "", $field);
$sortfield = explode('.', $field);
foreach ($sortfield as $id => $sfield) {
if (substr($sfield, - 1, 1) != '`') {
$sfield .= '`';
}
if ($sfield[0] != '`') {
$sfield = '`' . $sfield;
}
$sortfield[$id] = $sfield;
}
$field = implode('.', $sortfield);
if (! $first) {
$condition .= ' AND ';
}
if (! is_array($valoper) || ! isset($valoper['op']) || empty($valoper['op'])) {
$condition .= $field . ' LIKE :' . $cleanfield;
if (! is_array($valoper)) {
$query_fields[':' . $cleanfield] = '%' . $valoper . '%';
} else {
$query_fields[':' . $cleanfield] = '%' . $valoper['value'] . '%';
}
} elseif (in_array($valoper['op'], $ops)) {
$condition .= $field . ' ' . $valoper['op'] . ':' . $cleanfield;
$query_fields[':' . $cleanfield] = $valoper['value'] ?? '';
} else {
continue;
}
if ($first) {
$first = false;
}
}
}
return $condition;
}
/**
* return LIMIT clause when at least $sql_limit parameter is given via API
*
* @param int $sql_limit
* optional, limit resultset, default 0
* @param int $sql_offset
* optional, offset for limitation, default 0
*
* @return string
*/
protected function getLimit()
{
$limit = $this->getParam('sql_limit', true, 0);
$offset = $this->getParam('sql_offset', true, 0);
if (! is_numeric($limit)) {
$limit = 0;
}
if (! is_numeric($offset)) {
$offset = 0;
}
if ($limit > 0) {
return ' LIMIT ' . $offset . ',' . $limit;
}
return '';
}
/**
* return ORDER BY clause if parameter $sql_orderby parameter is given via API
*
* @param array $sql_orderby
* optional array with index = fieldname and value = ASC|DESC
* @param boolean $append
* optional append to ORDER BY clause rather then create new one, default false [internal]
*
* @return string
*/
protected function getOrderBy($append = false)
{
$orderby = $this->getParam('sql_orderby', true, array());
$order = "";
if (! empty($orderby)) {
if ($append) {
$order .= ", ";
} else {
$order .= " ORDER BY ";
}
$nat_fields = [
'`c`.`loginname`',
'`a`.`loginname`',
'`adminname`',
'`databasename`',
'`username`'
];
foreach ($orderby as $field => $by) {
$sortfield = explode('.', $field);
foreach ($sortfield as $id => $sfield) {
if (substr($sfield, - 1, 1) != '`') {
$sfield .= '`';
}
if ($sfield[0] != '`') {
$sfield = '`' . $sfield;
}
$sortfield[$id] = $sfield;
}
$field = implode('.', $sortfield);
$by = strtoupper($by);
if (! in_array($by, [
'ASC',
'DESC'
])) {
$by = 'ASC';
}
if (\Froxlor\Settings::Get('panel.natsorting') == 1 && in_array($field, $nat_fields)) {
// Acts similar to php's natsort(), found in one comment at http://my.opera.com/cpr/blog/show.dml/160556
$order .= "CONCAT( IF( ASCII( LEFT( " . $field . ", 5 ) ) > 57,
LEFT( " . $field . ", 1 ), 0 ),
IF( ASCII( RIGHT( " . $field . ", 1 ) ) > 57,
LPAD( " . $field . ", 255, '0' ),
LPAD( CONCAT( " . $field . ", '-' ), 255, '0' )
)) " . $by . ", ";
} else {
$order .= $field . " " . $by . ", ";
}
}
$order = substr($order, 0, - 2);
}
return $order;
}
/**
* return logger instance
*
@@ -257,15 +441,18 @@ abstract class ApiCommand extends ApiParameter
*
* @param string $command
* @param array|null $params
* @param boolean $internal
* optional whether called internally, default false
*
*
* @return array
*/
protected function apiCall($command = null, $params = null)
protected function apiCall($command = null, $params = null, $internal = false)
{
$_command = explode(".", $command);
$module = __NAMESPACE__ . "\Commands\\" . $_command[0];
$function = $_command[1];
$json_result = $module::getLocal($this->getUserData(), $params)->{$function}();
$json_result = $module::getLocal($this->getUserData(), $params, $internal)->{$function}();
return json_decode($json_result, true)['data'];
}
@@ -331,7 +518,7 @@ abstract class ApiCommand extends ApiParameter
$customer_ids[] = $customer['customerid'];
}
} else {
if (! empty($customer_hide_option) && \Froxlor\Settings::IsInList('panel.customer_hide_options', $customer_hide_option)) {
if (!$this->isInternal() && ! empty($customer_hide_option) && \Froxlor\Settings::IsInList('panel.customer_hide_options', $customer_hide_option)) {
throw new \Exception("You cannot access this resource", 405);
}
$customer_ids = array(
@@ -423,8 +610,12 @@ abstract class ApiCommand extends ApiParameter
"group" => $group,
"var" => $varname
), true, true);
$content = $default;
if ($result) {
$content = $result['value'] ?? $default;
}
// @fixme html_entity_decode
$content = html_entity_decode(\Froxlor\PhpHelper::replaceVariables((($result['value'] != '') ? $result['value'] : $default), $replace_arr));
$content = html_entity_decode(\Froxlor\PhpHelper::replaceVariables($content, $replace_arr));
return $content;
}

View File

@@ -25,6 +25,15 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
/**
* lists all admin entries
*
* @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
* @throws \Exception
* @return string json-encoded array count|list
@@ -33,17 +42,16 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
{
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list admins");
$query_fields = array();
$result_stmt = Database::prepare("
SELECT *
FROM `" . TABLE_PANEL_ADMINS . "`
ORDER BY `loginname` ASC
");
Database::pexecute($result_stmt, null, true, true);
FROM `" . TABLE_PANEL_ADMINS . "`" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
Database::pexecute($result_stmt, $query_fields, true, true);
$result = array();
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
}
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
@@ -51,6 +59,28 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* returns the total number of admins for the given admin
*
* @access admin
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_admins
FROM `" . TABLE_PANEL_ADMINS . "`
");
$result = Database::pexecute_first($result_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_admins']);
}
}
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* return an admin entry by either id or loginname
*
@@ -79,7 +109,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get admin '" . $result['loginname'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
throw new \Exception("Admin with " . $key . " could not be found", 404);
@@ -235,7 +265,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
'login' => $loginname
), true, true);
if (strtolower($loginname_check['loginname']) == strtolower($loginname) || strtolower($loginname_check_admin['loginname']) == strtolower($loginname)) {
if (($loginname_check && strtolower($loginname_check['loginname']) == strtolower($loginname)) || ($loginname_check_admin && strtolower($loginname_check_admin['loginname']) == strtolower($loginname))) {
\Froxlor\UI\Response::standard_error('loginnameexists', $loginname, true);
} elseif (preg_match('/^' . preg_quote(Settings::Get('customer.accountprefix'), '/') . '([0-9]+)/', $loginname)) {
// Accounts which match systemaccounts are not allowed, filtering them
@@ -334,7 +364,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result = $this->apiCall('Admins.get', array(
'id' => $adminid
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
}
throw new \Exception("Not allowed to execute given command.", 403);
@@ -647,7 +677,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result = $this->apiCall('Admins.get', array(
'id' => $result['adminid']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
}
}
@@ -749,7 +779,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted admin '" . $result['loginname'] . "'");
\Froxlor\User::updateCounters();
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -791,7 +821,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result['loginfail_count'] = 0;
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] unlocked admin '" . $result['loginname'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Froxlor\Api\Commands;
use Froxlor\Database\Database;
use Froxlor\Settings;
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* For the full copyright and license information, please view the COPYING
* file that was distributed with this source code. You can also view the
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
*
* @copyright (c) the authors
* @author Froxlor team <team@froxlor.org> (2010-)
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
* @package API
* @since 0.10.0
*
*/
class ApiKeys extends \Froxlor\Api\ApiCommand
{
public function listing()
{}
public function listingCount()
{}
}

View File

@@ -81,7 +81,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
$result = $this->apiCall('Certificates.get', array(
'id' => $domain['id']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Domain '" . $domain['domain'] . "' already has a certificate. Did you mean to call update?", 406);
}
@@ -122,7 +122,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
if (! $result) {
throw new \Exception("Domain '" . $domain['domain'] . "' does not have a certificate.", 412);
}
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
@@ -168,12 +168,21 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
$result = $this->apiCall('Certificates.get', array(
'id' => $domain['id']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
* lists all certificate entries
*
* @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
* @throws \Exception
* @return string json-encoded array count|list
@@ -188,7 +197,53 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
WHERE ";
$qry_params = array();
$query_fields = array();
if ($this->isAdmin() && $this->getUserDetail('customers_see_all') == '0') {
// admin with only customer-specific permissions
$certs_stmt_query .= "d.adminid = :adminid ";
$qry_params['adminid'] = $this->getUserDetail('adminid');
} elseif ($this->isAdmin() == false) {
// customer-area
$certs_stmt_query .= "d.customerid = :cid ";
$qry_params['cid'] = $this->getUserDetail('customerid');
} else {
$certs_stmt_query .= "1 ";
}
$certs_stmt = Database::prepare($certs_stmt_query . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
$qry_params = array_merge($qry_params, $query_fields);
Database::pexecute($certs_stmt, $qry_params, true, true);
$result = array();
while ($cert = $certs_stmt->fetch(\PDO::FETCH_ASSOC)) {
// respect froxlor-hostname
if ($cert['domainid'] == 0) {
$cert['domain'] = Settings::Get('system.hostname');
$cert['letsencrypt'] = Settings::Get('system.le_froxlor_enabled');
$cert['loginname'] = 'froxlor.panel';
}
$result[] = $cert;
}
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* returns the total number of certificates for the given user
*
* @access admin, customer
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
// select all my (accessable) certificates
$certs_stmt_query = "SELECT COUNT(*) as num_certs
FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` s
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON `d`.`id` = `s`.`domainid`
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` c ON `c`.`customerid` = `d`.`customerid`
WHERE ";
$qry_params = array();
if ($this->isAdmin() && $this->getUserDetail('customers_see_all') == '0') {
// admin with only customer-specific permissions
$certs_stmt_query .= "d.adminid = :adminid ";
@@ -201,21 +256,10 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
$certs_stmt_query .= "1 ";
}
$certs_stmt = Database::prepare($certs_stmt_query);
Database::pexecute($certs_stmt, $qry_params, true, true);
$result = array();
while ($cert = $certs_stmt->fetch(\PDO::FETCH_ASSOC)) {
// respect froxlor-hostname
if ($cert['domainid'] == 0) {
$cert['domain'] = Settings::Get('system.hostname');
$cert['letsencrypt'] = Settings::Get('system.le_froxlor_enabled');
$cert['loginname'] = 'froxlor.panel';
$result = Database::pexecute_first($certs_stmt, $qry_params, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_certs']);
}
$result[] = $cert;
}
return $this->response(200, "successfull", array(
'count' => count($result),
'list' => $result
));
}
/**
@@ -232,7 +276,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
if ($this->isAdmin() == false) {
$chk_stmt = Database::prepare("
SELECT d.domain FROM `" . TABLE_PANEL_DOMAINS . "` d
SELECT d.domain, d.letsencrypt FROM `" . TABLE_PANEL_DOMAINS . "` d
LEFT JOIN `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` s ON s.domainid = d.id
WHERE s.`id` = :id AND d.`customerid` = :cid
");
@@ -242,7 +286,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
));
} elseif ($this->isAdmin()) {
$chk_stmt = Database::prepare("
SELECT d.domain FROM `" . TABLE_PANEL_DOMAINS . "` d
SELECT d.domain, d.letsencrypt FROM `" . TABLE_PANEL_DOMAINS . "` d
LEFT JOIN `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` s ON s.domainid = d.id
WHERE s.`id` = :id" . ($this->getUserDetail('customers_see_all') == '0' ? " AND d.`adminid` = :aid" : ""));
$params = array(
@@ -255,7 +299,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
if ($chk == false && $this->getUserDetail('change_serversettings')) {
// check whether it might be the froxlor-vhost certificate
$chk_stmt = Database::prepare("
SELECT \"" . Settings::Get('system.hostname') . "\" as domain FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
SELECT \"" . Settings::Get('system.hostname') . "\" as domain, \"" . Settings::Get('system.le_froxlor_enabled') . "\" as letsencrypt FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
WHERE `id` = :id AND `domainid` = '0'");
$params = array(
'id' => $id
@@ -277,13 +321,16 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
Database::pexecute($del_stmt, array(
'id' => $id
));
// trigger removing of certificate from acme.sh if let's encrypt
if ($chk['letsencrypt'] == '1') {
\Froxlor\System\Cronjob::inserttask('12', $chk['domain']);
}
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] removed ssl-certificate for '" . $chk['domain'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Unable to determine SSL certificate. Maybe no access?", 406);
}
/**
* insert or update certificates entry
*

View File

@@ -51,7 +51,7 @@ class Cronjobs extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceE
'id' => $id
), true, true);
if ($result) {
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("cronjob with id #" . $id . " could not be found", 404);
}
@@ -119,7 +119,7 @@ class Cronjobs extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceE
$result = $this->apiCall('Cronjobs.get', array(
'id' => $id
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -127,6 +127,15 @@ class Cronjobs extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceE
/**
* lists all cronjob entries
*
* @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
* @throws \Exception
* @return string json-encoded array count|list
@@ -135,15 +144,15 @@ class Cronjobs extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceE
{
if ($this->isAdmin()) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list cronjobs");
$query_fields = array();
$result_stmt = Database::prepare("
SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` ORDER BY `module` ASC, `cronfile` ASC
");
Database::pexecute($result_stmt);
SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
Database::pexecute($result_stmt, $query_fields, true, true);
$result = array();
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
}
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
@@ -151,6 +160,27 @@ class Cronjobs extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceE
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* returns the total number of cronjobs
*
* @access admin
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
if ($this->isAdmin()) {
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_crons FROM `" . TABLE_PANEL_CRONRUNS . "` `c`
");
$result = Database::pexecute_first($result_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_crons']);
}
}
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* You cannot delete system cronjobs.
*/

View File

@@ -109,7 +109,7 @@ class CustomerBackups extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Re
\Froxlor\System\Cronjob::inserttask('20', $task_data);
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added customer-backup job for '" . $customer['loginname'] . "'. Target directory: " . $userpath);
return $this->response(200, "successfull", $task_data);
return $this->response(200, "successful", $task_data);
}
/**
@@ -137,6 +137,14 @@ class CustomerBackups extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Re
* optional, admin-only, select backup-jobs of a specific customer by id
* @param string $loginname
* optional, admin-only, select backup-jobs 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
* @throws \Exception
@@ -149,8 +157,9 @@ class CustomerBackups extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Re
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
// check whether there is a backup-job for this customer
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'");
Database::pexecute($sel_stmt);
$query_fields = array();
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
Database::pexecute($sel_stmt, $query_fields, true, true);
$result = array();
while ($entry = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
$entry['data'] = json_decode($entry['data'], true);
@@ -159,12 +168,43 @@ class CustomerBackups extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Re
}
}
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list customer-backups");
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* returns the total number of planned backups
*
* @param int $customerid
* optional, admin-only, select backup-jobs of a specific customer by id
* @param string $loginname
* optional, admin-only, select backup-jobs of a specific customer by loginname
*
* @access admin, customer
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
$this->validateAccess();
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
// check whether there is a backup-job for this customer
$result_count = 0;
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'");
Database::pexecute($sel_stmt, null, true, true);
while ($entry = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
$entry['data'] = json_decode($entry['data'], true);
if (in_array($entry['data']['customerid'], $customer_ids)) {
$result_count ++;
}
}
return $this->response(200, "successful", $result_count);
}
/**
* delete a planned backup-jobs by id, if called from an admin you need to specify the customerid/loginname
*
@@ -195,9 +235,9 @@ class CustomerBackups extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Re
if ($backupjob['id'] == $entry && in_array($backupjob['data']['customerid'], $customer_ids)) {
Database::pexecute($del_stmt, array(
'tid' => $entry
));
), true, true);
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted planned customer-backup #" . $entry);
return $this->response(200, "successfull", true);
return $this->response(200, "successful", true);
}
}
}

View File

@@ -25,6 +25,15 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
/**
* lists all customer entries
*
* @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
* @throws \Exception
* @return string json-encoded array count|list
@@ -33,25 +42,25 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
{
if ($this->isAdmin()) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list customers");
$query_fields = array();
$result_stmt = Database::prepare("
SELECT `c`.*, `a`.`loginname` AS `adminname`
FROM `" . TABLE_PANEL_CUSTOMERS . "` `c`, `" . TABLE_PANEL_ADMINS . "` `a`
WHERE " . ($this->getUserDetail('customers_see_all') ? '' : " `c`.`adminid` = :adminid AND ") . "
`c`.`adminid` = `a`.`adminid`
ORDER BY `c`.`loginname` ASC
");
`c`.`adminid` = `a`.`adminid`" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
$params = array();
if ($this->getUserDetail('customers_see_all') == '0') {
$params = array(
'adminid' => $this->getUserDetail('adminid')
);
}
$params = array_merge($params, $query_fields);
Database::pexecute($result_stmt, $params, true, true);
$result = array();
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
}
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
@@ -59,6 +68,34 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* returns the total number of customers for the given admin
*
* @access admin
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
if ($this->isAdmin()) {
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_customers
FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE " . ($this->getUserDetail('customers_see_all') ? "1" : " `adminid` = :adminid "));
$params = array();
if ($this->getUserDetail('customers_see_all') == '0') {
$params = array(
'adminid' => $this->getUserDetail('adminid')
);
}
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_customers']);
}
}
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* return a customer entry by either id or loginname
*
@@ -106,7 +143,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$result['custom_notes'] = "";
}
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get customer '" . $result['loginname'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
throw new \Exception("Customer with " . $key . " could not be found", 404);
@@ -146,7 +183,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
* optional, whether to show the content of custom_notes to the customer, default 0 (false)
* @param string $new_loginname
* optional, if empty generated automatically using customer-prefix and increasing number
* @param string $password
* @param string $new_customer_password
* optional, if empty generated automatically and send to the customer's email if $sendpassword is 1
* @param bool $sendpassword
* optional, whether to send the password to the customer after creation, default 0 (false)
@@ -374,7 +411,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
), true, true);
$mysql_maxlen = \Froxlor\Database\Database::getSqlUsernameLength() - strlen(Settings::Get('customer.mysqlprefix'));
if (strtolower($loginname_check['loginname']) == strtolower($loginname) || strtolower($loginname_check_admin['loginname']) == strtolower($loginname)) {
if (($loginname_check && strtolower($loginname_check['loginname']) == strtolower($loginname)) || ($loginname_check_admin && strtolower($loginname_check_admin['loginname']) == strtolower($loginname))) {
\Froxlor\UI\Response::standard_error('loginnameexists', $loginname, true);
} elseif (! \Froxlor\Validate\Validate::validateUsername($loginname, Settings::Get('panel.unix_names'), $mysql_maxlen)) {
if (strlen($loginname) > $mysql_maxlen) {
@@ -652,6 +689,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
'name' => $name,
'company' => $company
)),
'CUSTOMER_NO' => $customernumber,
'USERNAME' => $loginname,
'PASSWORD' => $password,
'SERVER_HOSTNAME' => $srv_hostname,
@@ -705,7 +743,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$result = $this->apiCall('Customers.get', array(
'loginname' => $loginname
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("No more resources available", 406);
}
@@ -1302,7 +1340,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$result = $this->apiCall('Customers.get', array(
'id' => $result['customerid']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
@@ -1372,7 +1410,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
'id' => $id
), true, true);
// first gather all domain-id's to clean up panel_domaintoip and dns-entries accordingly
// first gather all domain-id's to clean up panel_domaintoip, dns-entries and certificates accordingly
$did_stmt = Database::prepare("SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `customerid` = :id");
Database::pexecute($did_stmt, array(
'id' => $id
@@ -1388,6 +1426,11 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
Database::pexecute($stmt, array(
'did' => $row['id']
), true, true);
// remove domain->certificates entries
$stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = :did");
Database::pexecute($stmt, array(
'did' => $row['id']
), true, true);
}
// remove customer domains
$stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `customerid` = :id");
@@ -1530,7 +1573,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
\Froxlor\System\Cronjob::inserttask('10');
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted customer '" . $result['loginname'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -1572,7 +1615,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$result['loginfail_count'] = 0;
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] unlocked customer '" . $result['loginname'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -1642,7 +1685,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$result = $this->apiCall('Customers.get', array(
'id' => $c_result['customerid']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}

View File

@@ -96,7 +96,7 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
), true, true);
// duplicate check
if ($path_dupe_check['path'] == $path) {
if ($path_dupe_check && $path_dupe_check['path'] == $path) {
\Froxlor\UI\Response::standard_error('errordocpathdupe', $userpath, true);
}
@@ -128,7 +128,7 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$result = $this->apiCall('DirOptions.get', array(
'id' => $id
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
@@ -186,7 +186,7 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory options for '" . $result['path'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
$key = "id #" . $id;
throw new \Exception("Directory option with " . $key . " could not be found", 404);
@@ -275,7 +275,7 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$result = $this->apiCall('DirOptions.get', array(
'id' => $id
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
@@ -285,6 +285,14 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
* optional, admin-only, select directory-protections of a specific customer by id
* @param string $loginname
* optional, admin-only, select directory-protections 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
* @throws \Exception
@@ -298,21 +306,51 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$customer_ids = $this->getAllowedCustomerIds('extras.pathoptions');
$result = array();
$query_fields = array();
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_HTACCESS . "`
WHERE `customerid` IN (" . implode(', ', $customer_ids) . ")
");
Database::pexecute($result_stmt, null, true, true);
WHERE `customerid` IN (" . implode(', ', $customer_ids) . ")" . $this->getSearchWhere($query_fields, true) . $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() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-options");
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* returns the total number of accessable directory options
*
* @param int $customerid
* optional, admin-only, select directory-protections of a specific customer by id
* @param string $loginname
* optional, admin-only, select directory-protections of a specific customer by loginname
*
* @access admin, customer
* @throws \Exception
* @return string json-encoded array count|list
*/
public function listingCount()
{
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras')) {
throw new \Exception("You cannot access this resource", 405);
}
$customer_ids = $this->getAllowedCustomerIds('extras.pathoptions');
$result = array();
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_htaccess FROM `" . TABLE_PANEL_HTACCESS . "`
WHERE `customerid` IN (" . implode(', ', $customer_ids) . ")
");
$result = Database::pexecute_first($result_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_htaccess']);
}
}
/**
* delete a directory-options by id
*
@@ -373,10 +411,10 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
Database::pexecute($stmt, array(
"customerid" => $customer_data['customerid'],
"id" => $id
));
), true, true);
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'");
\Froxlor\System\Cronjob::inserttask('1');
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**

View File

@@ -81,7 +81,7 @@ class DirProtections extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Res
$password_enc = \Froxlor\System\Crypt::makeCryptPassword($password, true);
// duplicate check
if ($username_path_check['username'] == $username && $username_path_check['path'] == $path) {
if ($username_path_check && $username_path_check['username'] == $username && $username_path_check['path'] == $path) {
\Froxlor\UI\Response::standard_error('userpathcombinationdupe', '', true);
} elseif ($password == $username) {
\Froxlor\UI\Response::standard_error('passwordshouldnotbeusername', '', true);
@@ -111,7 +111,7 @@ class DirProtections extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Res
$result = $this->apiCall('DirProtections.get', array(
'id' => $id
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
@@ -173,7 +173,7 @@ class DirProtections extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Res
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory protection for '" . $result['path'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
throw new \Exception("Directory protection with " . $key . " could not be found", 404);
@@ -258,7 +258,7 @@ class DirProtections extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Res
$result = $this->apiCall('DirProtections.get', array(
'id' => $result['id']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
@@ -268,6 +268,14 @@ class DirProtections extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Res
* optional, admin-only, select directory-protections of a specific customer by id
* @param string $loginname
* optional, admin-only, select directory-protections 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
* @throws \Exception
@@ -281,21 +289,51 @@ class DirProtections extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Res
$customer_ids = $this->getAllowedCustomerIds('extras.directoryprotection');
$result = array();
$query_fields = array();
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_HTPASSWDS . "`
WHERE `customerid` IN (" . implode(', ', $customer_ids) . ")
");
Database::pexecute($result_stmt, null, true, true);
WHERE `customerid` IN (" . implode(', ', $customer_ids) . ")" . $this->getSearchWhere($query_fields, true) . $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() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-protections");
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* returns the total number of accessable directory protections
*
* @param int $customerid
* optional, admin-only, select directory-protections of a specific customer by id
* @param string $loginname
* optional, admin-only, select directory-protections of a specific customer by loginname
*
* @access admin, customer
* @throws \Exception
* @return string json-encoded array count|list
*/
public function listingCount()
{
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras')) {
throw new \Exception("You cannot access this resource", 405);
}
$customer_ids = $this->getAllowedCustomerIds('extras.directoryprotection');
$result = array();
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_htpasswd FROM `" . TABLE_PANEL_HTPASSWDS . "`
WHERE `customerid` IN (" . implode(', ', $customer_ids) . ")
");
$result = Database::pexecute_first($result_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_htpasswd']);
}
}
/**
* delete a directory-protection by either id or username
*
@@ -348,6 +386,6 @@ class DirProtections extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Res
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'");
\Froxlor\System\Cronjob::inserttask('1');
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
}

View File

@@ -309,7 +309,7 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$result = $this->apiCall('DomainZones.get', array(
'id' => $id
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
// return $errors
throw new \Exception(implode("\n", $errors));
@@ -360,7 +360,7 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$zonefile = (string) $zone;
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get dns-zone for '" . $result['domain'] . "'");
return $this->response(200, "successfull", explode("\n", $zonefile));
return $this->response(200, "successful", explode("\n", $zonefile));
}
/**
@@ -379,6 +379,14 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
* optional, the domain id
* @param string $domainname
* optional, the domain name
* @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
* @throws \Exception
@@ -404,21 +412,62 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
'domainname' => $domainname
));
$id = $result['id'];
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_DOMAIN_DNS . "` WHERE `domain_id` = :did");
Database::pexecute($sel_stmt, array(
'did' => $id
), true, true);
$query_fields = array();
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_DOMAIN_DNS . "` WHERE `domain_id` = :did" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
$query_fields['did'] = $id;
Database::pexecute($sel_stmt, $query_fields, true, true);
$result = [];
while ($row = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
}
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* returns the total number of domainzone-entries for given domain
*
* @param int $id
* optional, the domain id
* @param string $domainname
* optional, the domain name
*
* @access admin, customer
* @throws \Exception
* @return bool
*/
public function listingCount()
{
if (Settings::Get('system.dnsenabled') != '1') {
throw new \Exception("DNS service not enabled on this system", 405);
}
if ($this->isAdmin() == false && $this->getUserDetail('dnsenabled') != '1') {
throw new \Exception("You cannot access this resource", 405);
}
$id = $this->getParam('id', true, 0);
$dn_optional = ($id <= 0 ? false : true);
$domainname = $this->getParam('domainname', $dn_optional, '');
// get requested domain
$result = $this->apiCall('SubDomains.get', array(
'id' => $id,
'domainname' => $domainname
));
$id = $result['id'];
$sel_stmt = Database::prepare("SELECT COUNT(*) as num_dns FROM `" . TABLE_DOMAIN_DNS . "` WHERE `domain_id` = :did");
$result = Database::pexecute_first($sel_stmt, array(
'did' => $id
), true, true);
if ($result) {
return $this->response(200, "successful", $result['num_dns']);
}
}
/**
* deletes a domain-dns entry by id
*
@@ -462,8 +511,8 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
if ($del_stmt->rowCount() > 0) {
// re-generate bind configs
\Froxlor\System\Cronjob::inserttask('4');
return $this->response(200, "successfull", true);
return $this->response(200, "successful", true);
}
return $this->response(304, "successfull", true);
return $this->response(304, "successful", true);
}
}

View File

@@ -25,6 +25,17 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
/**
* lists all domain entries
*
* @param bool $with_ips
* optional, default true
* @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
* @throws \Exception
* @return string json-encoded array count|list
@@ -32,7 +43,9 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
public function listing()
{
if ($this->isAdmin()) {
$with_ips = $this->getParam('with_ips', true, true);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list domains");
$query_fields = array();
$result_stmt = Database::prepare("
SELECT
`d`.*, `c`.`loginname`, `c`.`deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`,
@@ -40,20 +53,55 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `ad` ON `d`.`aliasdomain`=`ad`.`id`
WHERE `d`.`parentdomainid`='0' " . ($this->getUserDetail('customers_see_all') ? '' : " AND `d`.`adminid` = :adminid ") . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
$params = array();
if ($this->getUserDetail('customers_see_all') == '0') {
$params['adminid'] = $this->getUserDetail('adminid');
}
$params = array_merge($params, $query_fields);
Database::pexecute($result_stmt, $params, true, true);
$result = array();
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$row['ipsandports'] = array();
if ($with_ips) {
$row['ipsandports'] = $this->getIpsForDomain($row['id']);
}
$result[] = $row;
}
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* returns the total number of accessable domains
*
* @access admin
* @throws \Exception
* @return string json-encoded array count|list
*/
public function listingCount()
{
if ($this->isAdmin()) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list domains");
$result_stmt = Database::prepare("
SELECT
COUNT(*) as num_domains
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `ad` ON `d`.`aliasdomain`=`ad`.`id`
WHERE `d`.`parentdomainid`='0' " . ($this->getUserDetail('customers_see_all') ? '' : " AND `d`.`adminid` = :adminid "));
$params = array();
if ($this->getUserDetail('customers_see_all') == '0') {
$params['adminid'] = $this->getUserDetail('adminid');
}
Database::pexecute($result_stmt, $params);
$result = array();
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_domains']);
}
return $this->response(200, "successfull", array(
'count' => count($result),
'list' => $result
));
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -65,6 +113,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
* optional, the domain-id
* @param string $domainname
* optional, the domainname
* @param bool $with_ips
* optional, default true
* @param bool $no_std_subdomain
* optional, default false
*
@@ -78,6 +128,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$id = $this->getParam('id', true, 0);
$dn_optional = ($id <= 0 ? false : true);
$domainname = $this->getParam('domainname', $dn_optional, '');
$with_ips = $this->getParam('with_ips', true, true);
$no_std_subdomain = $this->getParam('no_std_subdomain', true, false);
// convert possible idn domain to punycode
@@ -100,8 +151,12 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
}
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$result['ipsandports'] = array();
if ($with_ips) {
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
}
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get domain '" . $result['domain'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
throw new \Exception("Domain with " . $key . " could not be found", 404);
@@ -109,6 +164,35 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* get ips connected to given domain as array
*
* @param number $domain_id
* @param bool $ssl_only
* optional, return only ssl enabled ip's, default false
* @return array
*/
private function getIpsForDomain($domain_id = 0, $ssl_only = false)
{
$resultips_stmt = Database::prepare("
SELECT `ips`.* FROM `" . TABLE_DOMAINTOIP . "` AS `dti`, `" . TABLE_PANEL_IPSANDPORTS . "` AS `ips`
WHERE `dti`.`id_ipandports` = `ips`.`id` AND `dti`.`id_domain` = :domainid " . ($ssl_only ? " AND `ips`.`ssl` = '1'" : ""));
Database::pexecute($resultips_stmt, array(
'domainid' => $domain_id
));
$ipandports = array();
while ($rowip = $resultips_stmt->fetch(\PDO::FETCH_ASSOC)) {
if (filter_var($rowip['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$rowip['is_ipv6'] = true;
}
$ipandports[] = $rowip;
}
return $ipandports;
}
/**
* add new domain entry
*
@@ -177,6 +261,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
* optional, list of ssl-enabled ip/port id's to assign to this domain, default empty
* @param bool $dont_use_default_ssl_ipandport_if_empty
* optional, do NOT set the systems default ssl ip addresses if none are given via $ssl_ipandport parameter
* @param bool $sslenabled
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default 1 (true)
* @param bool $http2
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default 0 (false)
* @param int $hsts_maxage
@@ -187,6 +273,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
* optional whether or not to preload HSTS header value
* @param bool $ocsp_stapling
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
* @param bool $honorcipherorder
* optional whether to honor the (server) cipher order for this domain. default 0 (false), requires SSL
* @param bool $sessiontickets
* optional whether to enable or disable TLS sessiontickets (RFC 5077) for this domain. default 1 (true), requires SSL
* @param bool $override_tls
* optional whether or not to override system-tls settings like protocol, ssl-ciphers and if applicable tls-1.3 ciphers, requires change_serversettings flag for the admin, default false
* @param array $ssl_protocols
@@ -241,11 +331,14 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$letsencrypt = $this->getBoolParam('letsencrypt', true, 0);
$dont_use_default_ssl_ipandport_if_empty = $this->getBoolParam('dont_use_default_ssl_ipandport_if_empty', true, 0);
$p_ssl_ipandports = $this->getParam('ssl_ipandport', true, $dont_use_default_ssl_ipandport_if_empty ? array() : explode(',', Settings::Get('system.defaultsslip')));
$sslenabled = $this->getBoolParam('sslenabled', true, 1);
$http2 = $this->getBoolParam('http2', true, 0);
$hsts_maxage = $this->getParam('hsts_maxage', true, 0);
$hsts_sub = $this->getBoolParam('hsts_sub', true, 0);
$hsts_preload = $this->getBoolParam('hsts_preload', true, 0);
$ocsp_stapling = $this->getBoolParam('ocsp_stapling', true, 0);
$honorcipherorder = $this->getBoolParam('honorcipherorder', true, 0);
$sessiontickets = $this->getBoolParam('sessiontickets', true, 1);
$override_tls = $this->getBoolParam('override_tls', true, 0);
$p_ssl_protocols = array();
@@ -261,7 +354,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
}
// validation
if ($p_domain == Settings::Get('system.hostname')) {
$p_domain = strtolower($p_domain);
if ($p_domain == strtolower(Settings::Get('system.hostname'))) {
\Froxlor\UI\Response::standard_error('admin_domain_emailsystemhostname', '', true);
}
@@ -580,9 +674,9 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
), '', true);
} elseif ($customerid == 0) {
\Froxlor\UI\Response::standard_error('adduserfirst', '', true);
} elseif (strtolower($domain_check['domain']) == strtolower($domain)) {
} elseif ($domain_check && strtolower($domain_check['domain']) == strtolower($domain)) {
\Froxlor\UI\Response::standard_error('domainalreadyexists', $idna_convert->decode($domain), true);
} elseif ($aliasdomain_check['id'] != $aliasdomain) {
} elseif ($aliasdomain_check && $aliasdomain_check['id'] != $aliasdomain) {
\Froxlor\UI\Response::standard_error('domainisaliasorothercustomer', '', true);
} else {
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
@@ -590,6 +684,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$ins_data = array(
'domain' => $domain,
'domain_ace' => $idna_convert->decode($domain),
'customerid' => $customerid,
'adminid' => $adminid,
'documentroot' => $documentroot,
@@ -629,12 +724,16 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
'override_tls' => $override_tls,
'ssl_protocols' => implode(",", $ssl_protocols),
'ssl_cipher_list' => $ssl_cipher_list,
'tlsv13_cipher_list' => $tlsv13_cipher_list
'tlsv13_cipher_list' => $tlsv13_cipher_list,
'sslenabled' => $sslenabled,
'honorcipherorder' => $honorcipherorder,
'sessiontickets' => $sessiontickets
);
$ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_PANEL_DOMAINS . "` SET
`domain` = :domain,
`domain_ace` = :domain_ace,
`customerid` = :customerid,
`adminid` = :adminid,
`documentroot` = :documentroot,
@@ -677,7 +776,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
`override_tls` = :override_tls,
`ssl_protocols` = :ssl_protocols,
`ssl_cipher_list` = :ssl_cipher_list,
`tlsv13_cipher_list` = :tlsv13_cipher_list
`tlsv13_cipher_list` = :tlsv13_cipher_list,
`ssl_enabled` = :sslenabled,
`ssl_honorcipherorder` = :honorcipherorder,
`ssl_sessiontickets`= :sessiontickets
");
Database::pexecute($ins_stmt, $ins_data, true, true);
$domainid = Database::lastInsertId();
@@ -726,7 +828,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$result = $this->apiCall('Domains.get', array(
'domainname' => $domain
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
}
throw new \Exception("No more resources available", 406);
@@ -782,7 +884,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
* @param bool $include_specialsettings
* optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false
* @param bool $specialsettingsforsubdomains
* optional, whether to apply specialsettings to all subdomains of this domain, default 0 (false)
* optional, whether to apply specialsettings to all subdomains of this domain, default is read from setting system.apply_specialsettings_default
* @param bool $notryfiles
* optional, [nginx only] do not generate the default try-files directive, default 0 (false)
* @param bool $writeaccesslog
@@ -794,7 +896,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
* @param bool $phpenabled
* optional, whether php is enabled for this domain, default 0 (false)
* @param bool $phpsettingsforsubdomains
* optional, whether to apply php-setting to apply to all subdomains of this domain, default 0 (false)
* optional, whether to apply php-setting to apply to all subdomains of this domain, default is read from setting system.apply_phpconfigs_default
* @param bool $openbasedir
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
* @param int $phpsettingid
@@ -808,7 +910,11 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
* @param bool $letsencrypt
* optional, whether to generate a Let's Encrypt certificate for this domain, default false; requires SSL to be enabled
* @param array $ssl_ipandport
* optional, list of ssl-enabled ip/port id's to assign to this domain
* optional, list of ssl-enabled ip/port id's to assign to this domain, if left empty, the current set value is being used, to remove all ssl ips use $remove_ssl_ipandport
* @param bool $remove_ssl_ipandport
* optional, if set to true and no $ssl_ipandport value is given, the ip's get removed, otherwise, the currently set value is used, default false
* @param bool $sslenabled
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default 1 (true)
* @param bool $http2
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default 0 (false)
* @param int $hsts_maxage
@@ -819,6 +925,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
* optional whether or not to preload HSTS header value
* @param bool $ocsp_stapling
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
* @param bool $honorcipherorder
* optional whether to honor the (server) cipher order for this domain. default 0 (false), requires SSL
* @param bool $sessiontickets
* optional whether to enable or disable TLS sessiontickets (RFC 5077) for this domain. default 1 (true), requires SSL
*
* @access admin
* @throws \Exception
@@ -862,25 +972,31 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$specialsettings = $this->getParam('specialsettings', true, $result['specialsettings']);
$ssl_specialsettings = $this->getParam('ssl_specialsettings', true, $result['ssl_specialsettings']);
$include_specialsettings = $this->getBoolParam('include_specialsettings', true, $result['include_specialsettings']);
$ssfs = $this->getBoolParam('specialsettingsforsubdomains', true, 0);
$ssfs = $this->getBoolParam('specialsettingsforsubdomains', true, \Froxlor\Settings::Get('system.apply_specialsettings_default'));
$notryfiles = $this->getBoolParam('notryfiles', true, $result['notryfiles']);
$writeaccesslog = $this->getBoolParam('writeaccesslog', true, $result['writeaccesslog']);
$writeerrorlog = $this->getBoolParam('writeerrorlog', true, $result['writeerrorlog']);
$documentroot = $this->getParam('documentroot', true, $result['documentroot']);
$phpenabled = $this->getBoolParam('phpenabled', true, $result['phpenabled']);
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, 0);
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, \Froxlor\Settings::Get('system.apply_phpconfigs_default'));
$openbasedir = $this->getBoolParam('openbasedir', true, $result['openbasedir']);
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
$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']);
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, $result['ssl_redirect']);
$letsencrypt = $this->getBoolParam('letsencrypt', true, $result['letsencrypt']);
$p_ssl_ipandports = $this->getParam('ssl_ipandport', true, array());
$remove_ssl_ipandport = $this->getBoolParam('remove_ssl_ipandport', true, 0);
$p_ssl_ipandports = $this->getParam('ssl_ipandport', true, $remove_ssl_ipandport ? array(
- 1
) : null);
$sslenabled = $this->getBoolParam('sslenabled', true, $result['ssl_enabled']);
$http2 = $this->getBoolParam('http2', true, $result['http2']);
$hsts_maxage = $this->getParam('hsts_maxage', true, $result['hsts']);
$hsts_sub = $this->getBoolParam('hsts_sub', true, $result['hsts_sub']);
$hsts_preload = $this->getBoolParam('hsts_preload', true, $result['hsts_preload']);
$ocsp_stapling = $this->getBoolParam('ocsp_stapling', true, $result['ocsp_stapling']);
$honorcipherorder = $this->getBoolParam('honorcipherorder', true, $result['ssl_honorcipherorder']);
$sessiontickets = $this->getBoolParam('sessiontickets', true, $result['ssl_sessiontickets']);
$override_tls = $this->getBoolParam('override_tls', true, $result['override_tls']);
@@ -1109,7 +1225,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$writeaccesslog = $result['writeaccesslog'];
$writeerrorlog = $result['writeerrorlog'];
$documentroot = $result['documentroot'];
$ssl_protocols = $p_ssl_protocols;
$override_tls = $result['override_tls'];
}
@@ -1158,14 +1274,24 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
// check non-ssl IP
$ipandports = $this->validateIpAddresses($p_ipandports, false, $result['id']);
// check ssl IP
if (empty($p_ssl_ipandports) || (! is_array($p_ssl_ipandports) && is_null($p_ssl_ipandports))) {
foreach ($result['ipsandports'] as $ip) {
if ($ip['ssl'] == 1) {
$p_ssl_ipandports[] = $ip['id'];
}
}
}
$ssl_ipandports = array();
if (Settings::Get('system.use_ssl') == "1" && ! empty($p_ssl_ipandports)) {
if (Settings::Get('system.use_ssl') == "1" && ! empty($p_ssl_ipandports) && $p_ssl_ipandports[0] != - 1) {
$ssl_ipandports = $this->validateIpAddresses($p_ssl_ipandports, true, $result['id']);
if ($this->getUserDetail('change_serversettings') == '1') {
$ssl_specialsettings = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $ssl_specialsettings), 'ssl_specialsettings', '/^[^\0]*$/', '', array(), true);
}
}
if ($remove_ssl_ipandport || (! empty($p_ssl_ipandports) && $p_ssl_ipandports[0] == - 1)) {
$ssl_ipandports = array();
}
if (Settings::Get('system.use_ssl') == "0" || empty($ssl_ipandports)) {
$ssl_redirect = 0;
$letsencrypt = 0;
@@ -1316,6 +1442,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
Database::pexecute($del_stmt, array(
'id' => $id
), true, true);
// remove domain from acme.sh / lets encrypt if used
\Froxlor\System\Cronjob::inserttask('12', $result['domain']);
}
$updatechildren = '';
@@ -1448,6 +1576,9 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$update_data['ssl_protocols'] = implode(",", $ssl_protocols);
$update_data['ssl_cipher_list'] = $ssl_cipher_list;
$update_data['tlsv13_cipher_list'] = $tlsv13_cipher_list;
$update_data['sslenabled'] = $sslenabled;
$update_data['honorcipherorder'] = $honorcipherorder;
$update_data['sessiontickets'] = $sessiontickets;
$update_data['id'] = $id;
$update_stmt = Database::prepare("
@@ -1490,7 +1621,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
`override_tls` = :override_tls,
`ssl_protocols` = :ssl_protocols,
`ssl_cipher_list` = :ssl_cipher_list,
`tlsv13_cipher_list` = :tlsv13_cipher_list
`tlsv13_cipher_list` = :tlsv13_cipher_list,
`ssl_enabled` = :sslenabled,
`ssl_honorcipherorder` = :honorcipherorder,
`ssl_sessiontickets` = :sessiontickets
WHERE `id` = :id
");
Database::pexecute($update_stmt, $update_data, true, true);
@@ -1501,10 +1635,15 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$_update_data['openbasedir'] = $openbasedir;
$_update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
$_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests;
$_update_data['notryfiles'] = $notryfiles;
$_update_data['writeaccesslog'] = $writeaccesslog;
$_update_data['writeerrorlog'] = $writeerrorlog;
$_update_data['override_tls'] = $override_tls;
$_update_data['ssl_protocols'] = implode(",", $ssl_protocols);
$_update_data['ssl_cipher_list'] = $ssl_cipher_list;
$_update_data['tlsv13_cipher_list'] = $tlsv13_cipher_list;
$_update_data['honorcipherorder'] = $honorcipherorder;
$_update_data['sessiontickets'] = $sessiontickets;
$_update_data['parentdomainid'] = $id;
// if php config is to be set for all subdomains, check here
@@ -1513,7 +1652,6 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$_update_data['phpsettingid'] = $phpsettingid;
$update_phpconfig = ", `phpsettingid` = :phpsettingid";
}
// if we have no more ssl-ip's for this domain,
// all its subdomains must have "ssl-redirect = 0"
// and disable let's encrypt
@@ -1530,10 +1668,15 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
`openbasedir` = :openbasedir,
`mod_fcgid_starter` = :mod_fcgid_starter,
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
`notryfiles` = :notryfiles,
`writeaccesslog` = :writeaccesslog,
`writeerrorlog` = :writeerrorlog,
`override_tls` = :override_tls,
`ssl_protocols` = :ssl_protocols,
`ssl_cipher_list` = :ssl_cipher_list,
`tlsv13_cipher_list` = :tlsv13_cipher_list
`tlsv13_cipher_list` = :tlsv13_cipher_list,
`ssl_honorcipherorder` = :honorcipherorder,
`ssl_sessiontickets` = :sessiontickets
" . $update_phpconfig . $upd_specialsettings . $updatechildren . $update_sslredirect . "
WHERE `parentdomainid` = :parentdomainid
");
@@ -1625,7 +1768,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$idna_convert = new \Froxlor\Idna\IdnaWrapper();
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] updated domain '" . $idna_convert->decode($result['domain']) . "'");
return $this->response(200, "successfull", $update_data);
$result = $this->apiCall('Domains.get', array(
'domainname' => $result['domain']
));
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -1786,7 +1932,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
\Froxlor\System\Cronjob::inserttask('1');
// Using nameserver, insert a task which rebuilds the server config
\Froxlor\System\Cronjob::inserttask('4');
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -1858,8 +2004,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
} elseif ($edit_id > 0) {
// set currently used ip's
$ipsresult_stmt = Database::prepare("
SELECT `id_ipandports` FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
");
SELECT d2i.`id_ipandports`
FROM `" . TABLE_DOMAINTOIP . "` d2i
LEFT JOIN `" . TABLE_PANEL_IPSANDPORTS . "` i ON i.id = d2i.id_ipandports
WHERE d2i.`id_domain` = :id AND i.`ssl` = " . ($ssl ? "'1'" : "'0'"));
Database::pexecute($ipsresult_stmt, array(
'id' => $edit_id
), true, true);

View File

@@ -100,8 +100,8 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
// alternative email address to send info to
if (Settings::Get('panel.sendalternativemail') == 1) {
$alternative_email = $idna_convert->encode(\Froxlor\Validate\Validate::validate($alternative_email, 'alternative_email', '', '', array(), true));
if (! \Froxlor\Validate\Validate::validateEmail($alternative_email)) {
\Froxlor\UI\Response::standard_error('emailiswrong', $alternative_email, true);
if (!empty($alternative_email) && ! \Froxlor\Validate\Validate::validateEmail($alternative_email)) {
\Froxlor\UI\Response::standard_error('alternativeemailiswrong', $alternative_email, true);
}
} else {
$alternative_email = '';
@@ -192,7 +192,12 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
$replace_arr = array(
'EMAIL' => $email_full,
'USERNAME' => $username,
'PASSWORD' => $password
'PASSWORD' => $password,
'SALUTATION' => \Froxlor\User::getCorrectUserSalutation($customer),
'NAME' => $customer['name'],
'FIRSTNAME' => $customer['firstname'],
'COMPANY' => $customer['company'],
'CUSTOMER_NO' => $customer['customernumber']
);
// get the customers admin
@@ -231,7 +236,7 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
$this->mailer()->clearAddresses();
// customer wants to send the e-mail to an alternative email address too
if (Settings::Get('panel.sendalternativemail') == 1) {
if (Settings::Get('panel.sendalternativemail') == 1 && !empty($alternative_email)) {
// get template for mail subject
$mail_subject = $this->getMailTemplate($customer, 'mails', 'pop_success_alternative_subject', $replace_arr, $this->lng['mails']['pop_success_alternative']['subject']);
// get template for mail body
@@ -268,7 +273,7 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
$result = $this->apiCall('Emails.get', array(
'emailaddr' => $result['email_full']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("No more resources available", 406);
}
@@ -384,16 +389,25 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
$result = $this->apiCall('Emails.get', array(
'emailaddr' => $result['email_full']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
* You cannot directly list email forwarders.
* You cannot directly list email accounts.
* You need to call Emails.listing()
*/
public function listing()
{
throw new \Exception('You cannot directly list email forwarders. You need to call Emails.listing()', 303);
throw new \Exception('You cannot directly list email accounts. You need to call Emails.listing()', 303);
}
/**
* You cannot directly count email accounts.
* You need to call Emails.listingCount()
*/
public function listingCount()
{
throw new \Exception('You cannot directly count email accounts. You need to call Emails.listingCount()', 303);
}
/**
@@ -478,6 +492,6 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $quota);
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email account for '" . $result['email_full'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
}

View File

@@ -102,18 +102,18 @@ class EmailForwarders extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Re
$result = $this->apiCall('Emails.get', array(
'emailaddr' => $result['email_full']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("No more resources available", 406);
}
/**
* You cannot directly get an email forwarder.
* You need to call Emails.get()
* Try EmailForwarders.listing()
*/
public function get()
{
throw new \Exception('You cannot directly get an email forwarder. You need to call Emails.get()', 303);
throw new \Exception('You cannot directly get an email forwarder. Try EmailForwarders.listing()', 303);
}
/**
@@ -126,12 +126,91 @@ class EmailForwarders extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Re
}
/**
* You cannot directly list email forwarders.
* You need to call Emails.listing()
* List email forwarders for a given email address
*
* @param int $id
* optional, the email-address-id
* @param string $emailaddr
* optional, the email-address to delete the forwarder from
* @param int $customerid
* optional, admin-only, the customer-id
* @param string $loginname
* optional, admin-only, the loginname
*
* @access admin,customer
* @throws \Exception
* @return string json-encoded array count|list
*/
public function listing()
{
throw new \Exception('You cannot directly list email forwarders. You need to call Emails.listing()', 303);
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
throw new \Exception("You cannot access this resource", 405);
}
// parameter
$id = $this->getParam('id', true, 0);
$ea_optional = ($id <= 0 ? false : true);
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
// validation
$result = $this->apiCall('Emails.get', array(
'id' => $id,
'emailaddr' => $emailaddr
));
$id = $result['id'];
$result['destination'] = explode(' ', $result['destination']);
$destination = array();
foreach ($result['destination'] as $index => $address) {
$destination[] = [
'id' => $index,
'address' => $address
];
}
return $this->response(200, "successful", [
'count' => count($destination),
'list' => $destination
]);
}
/**
* count email forwarders for a given email address
*
* @param int $id
* optional, the email-address-id
* @param string $emailaddr
* optional, the email-address to delete the forwarder from
* @param int $customerid
* optional, admin-only, the customer-id
* @param string $loginname
* optional, admin-only, the loginname
*
* @access admin,customer
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
throw new \Exception("You cannot access this resource", 405);
}
// parameter
$id = $this->getParam('id', true, 0);
$ea_optional = ($id <= 0 ? false : true);
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
// validation
$result = $this->apiCall('Emails.get', array(
'id' => $id,
'emailaddr' => $emailaddr
));
$id = $result['id'];
$result['destination'] = explode(' ', $result['destination']);
return $this->response(200, "successful", count($result['destination']));
}
/**
@@ -201,7 +280,7 @@ class EmailForwarders extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Re
$result = $this->apiCall('Emails.get', array(
'emailaddr' => $result['email_full']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Unknown forwarder id", 404);
}

View File

@@ -62,9 +62,10 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
}
// check domain and whether it's an email-enabled domain
// use internal call because the customer might have 'domains' in customer_hide_options
$domain_check = $this->apiCall('SubDomains.get', array(
'domainname' => $domain
));
), true);
if ($domain_check['isemaildomain'] == 0) {
\Froxlor\UI\Response::standard_error('maindomainnonexist', $domain, true);
}
@@ -106,11 +107,13 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
);
$email_check = Database::pexecute_first($stmt, $params, true, true);
if ($email_check) {
if (strtolower($email_check['email_full']) == strtolower($email_full)) {
\Froxlor\UI\Response::standard_error('emailexistalready', $email_full, true);
} elseif ($email_check['email'] == $email) {
\Froxlor\UI\Response::standard_error('youhavealreadyacatchallforthisdomain', '', true);
}
}
$stmt = Database::prepare("
INSERT INTO `" . TABLE_MAIL_VIRTUAL . "` SET
@@ -137,7 +140,7 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result = $this->apiCall('Emails.get', array(
'emailaddr' => $email_full
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("No more resources available", 406);
}
@@ -173,7 +176,7 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get email address '" . $result['email_full'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
$key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'");
throw new \Exception("Email address with " . $key . " could not be found", 404);
@@ -233,6 +236,19 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$iscatchall = '1';
$email_parts = explode('@', $result['email_full']);
$email = '@' . $email_parts[1];
// catchall check
$stmt = Database::prepare("
SELECT `email_full` FROM `" . TABLE_MAIL_VIRTUAL . "`
WHERE `email` = :email AND `customerid` = :cid AND `iscatchall` = '1'
");
$params = array(
"email" => $email,
"cid" => $customer['customerid']
);
$email_check = Database::pexecute_first($stmt, $params, true, true);
if ($email_check) {
\Froxlor\UI\Response::standard_error('youhavealreadyacatchallforthisdomain', '', true);
}
} else {
$iscatchall = '0';
$email = $result['email_full'];
@@ -255,7 +271,7 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result = $this->apiCall('Emails.get', array(
'emailaddr' => $result['email_full']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
@@ -265,6 +281,14 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
* 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
* @throws \Exception
@@ -274,24 +298,52 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
{
$customer_ids = $this->getAllowedCustomerIds('email');
$result = array();
$query_fields = array();
$result_stmt = Database::prepare("
SELECT m.`id`, m.`domainid`, m.`email`, m.`email_full`, m.`iscatchall`, u.`quota`, m.`destination`, m.`popaccountid`, d.`domain`, u.`mboxsize`
FROM `" . TABLE_MAIL_VIRTUAL . "` m
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`)
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`)
WHERE m.`customerid` IN (" . implode(", ", $customer_ids) . ")
");
Database::pexecute($result_stmt, null, true, true);
WHERE m.`customerid` IN (" . implode(", ", $customer_ids) . ")" . $this->getSearchWhere($query_fields, true) . $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() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list email-addresses");
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* returns the total number of accessable email addresses
*
* @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
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
$customer_ids = $this->getAllowedCustomerIds('email');
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_emails
FROM `" . TABLE_MAIL_VIRTUAL . "` m
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`)
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`)
WHERE m.`customerid` IN (" . implode(", ", $customer_ids) . ")
");
$result = Database::pexecute_first($result_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_emails']);
}
}
/**
* delete an email address by either id or username
*
@@ -366,6 +418,6 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
Customers::decreaseUsage($customer['customerid'], 'emails_used');
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email address '" . $result['email_full'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
}

View File

@@ -24,6 +24,15 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
/**
* lists all fpm-daemon entries
*
* @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
* @throws \Exception
* @return string json-encoded array count|list
@@ -32,21 +41,18 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
{
if ($this->isAdmin()) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list fpm-daemons");
$result = Database::query("
SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "` ORDER BY `description` ASC
");
$query_fields = array();
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "`" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
Database::pexecute($result_stmt, $query_fields, true, true);
$fpmdaemons = array();
while ($row = $result->fetch(\PDO::FETCH_ASSOC)) {
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$query_params = array(
'id' => $row['id']
);
$query = "SELECT * FROM `" . TABLE_PANEL_PHPCONFIGS . "` WHERE `fpmsettingid` = :id";
$configresult_stmt = Database::prepare($query);
$configresult_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_PHPCONFIGS . "` WHERE `fpmsettingid` = :id");
Database::pexecute($configresult_stmt, $query_params, true, true);
$configs = array();
@@ -64,7 +70,7 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$fpmdaemons[] = $row;
}
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($fpmdaemons),
'list' => $fpmdaemons
));
@@ -72,6 +78,27 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* returns the total number of accessable fpm daemons
*
* @access admin
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
if ($this->isAdmin()) {
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_fpms FROM `" . TABLE_PANEL_FPMDAEMONS . "`
");
$result = Database::pexecute_first($result_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_fpms']);
}
}
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* return a fpm-daemon entry by id
*
@@ -94,7 +121,7 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
'id' => $id
), true, true);
if ($result) {
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("fpm-daemon with id #" . $id . " could not be found", 404);
}
@@ -108,21 +135,23 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
* @param string $reload_cmd
* @param string $config_dir
* @param string $pm
* optional, process-manager, one of 'static', 'dynamic' or 'ondemand', default 'static'
* optional, process-manager, one of 'static', 'dynamic' or 'ondemand', default 'dynamic'
* @param int $max_children
* optional, default 0
* optional, default 5
* @param int $start_servers
* optional, default 0
* optional, default 2
* @param int $min_spare_servers
* optional, default 0
* optional, default 1
* @param int $max_spare_servers
* optional, default 0
* optional, default 3
* @param int $max_requests
* optional, default 0
* @param int $idle_timeout
* optional, default 0
* optional, default 10
* @param string $limit_extensions
* optional, limit execution to the following extensions, default '.php'
* @param string $custom_config
* optional, custom settings appended to phpfpm pool configuration
*
* @access admin
* @throws \Exception
@@ -138,14 +167,15 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$config_dir = $this->getParam('config_dir');
// parameters
$pmanager = $this->getParam('pm', true, 'static');
$max_children = $this->getParam('max_children', true, 0);
$start_servers = $this->getParam('start_servers', true, 0);
$min_spare_servers = $this->getParam('min_spare_servers', true, 0);
$max_spare_servers = $this->getParam('max_spare_servers', true, 0);
$pmanager = $this->getParam('pm', true, 'dynamic');
$max_children = $this->getParam('max_children', true, 5);
$start_servers = $this->getParam('start_servers', true, 2);
$min_spare_servers = $this->getParam('min_spare_servers', true, 1);
$max_spare_servers = $this->getParam('max_spare_servers', true, 3);
$max_requests = $this->getParam('max_requests', true, 0);
$idle_timeout = $this->getParam('idle_timeout', true, 0);
$idle_timeout = $this->getParam('idle_timeout', true, 10);
$limit_extensions = $this->getParam('limit_extensions', true, '.php');
$custom_config = $this->getParam('custom_config', true, '');
// validation
$description = \Froxlor\Validate\Validate::validate($description, 'description', '', '', array(), true);
@@ -179,7 +209,8 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
`max_spare_servers` = :max_spare_servers,
`max_requests` = :max_requests,
`idle_timeout` = :idle_timeout,
`limit_extensions` = :limit_extensions
`limit_extensions` = :limit_extensions,
`custom_config` = :custom_config
");
$ins_data = array(
'desc' => $description,
@@ -192,7 +223,8 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
'max_spare_servers' => $max_spare_servers,
'max_requests' => $max_requests,
'idle_timeout' => $idle_timeout,
'limit_extensions' => $limit_extensions
'limit_extensions' => $limit_extensions,
'custom_config' => $custom_config
);
Database::pexecute($ins_stmt, $ins_data);
$id = Database::lastInsertId();
@@ -202,7 +234,7 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$result = $this->apiCall('FpmDaemons.get', array(
'id' => $id
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -219,21 +251,23 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
* @param string $config_dir
* optional
* @param string $pm
* optional, process-manager, one of 'static', 'dynamic' or 'ondemand', default 'static'
* optional, process-manager, one of 'static', 'dynamic' or 'ondemand', default 'dynamic'
* @param int $max_children
* optional, default 0
* optional, default 5
* @param int $start_servers
* optional, default 0
* optional, default 2
* @param int $min_spare_servers
* optional, default 0
* optional, default 1
* @param int $max_spare_servers
* optional, default 0
* optional, default 3
* @param int $max_requests
* optional, default 0
* @param int $idle_timeout
* optional, default 0
* optional, default 10
* @param string $limit_extensions
* optional, limit execution to the following extensions, default '.php'
* @param string $custom_config
* optional, custom settings appended to phpfpm pool configuration
*
* @access admin
* @throws \Exception
@@ -262,6 +296,7 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$max_requests = $this->getParam('max_requests', true, $result['max_requests']);
$idle_timeout = $this->getParam('idle_timeout', true, $result['idle_timeout']);
$limit_extensions = $this->getParam('limit_extensions', true, $result['limit_extensions']);
$custom_config = $this->getParam('custom_config', true, $result['custom_config']);
// validation
$description = \Froxlor\Validate\Validate::validate($description, 'description', '', '', array(), true);
@@ -295,7 +330,8 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
`max_spare_servers` = :max_spare_servers,
`max_requests` = :max_requests,
`idle_timeout` = :idle_timeout,
`limit_extensions` = :limit_extensions
`limit_extensions` = :limit_extensions,
`custom_config` = :custom_config
WHERE `id` = :id
");
$upd_data = array(
@@ -310,6 +346,7 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
'max_requests' => $max_requests,
'idle_timeout' => $idle_timeout,
'limit_extensions' => $limit_extensions,
'custom_config' => $custom_config,
'id' => $id
);
Database::pexecute($upd_stmt, $upd_data, true, true);
@@ -319,7 +356,7 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$result = $this->apiCall('FpmDaemons.get', array(
'id' => $id
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -365,7 +402,7 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
\Froxlor\System\Cronjob::inserttask('1');
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}

View File

@@ -74,7 +74,7 @@ class Froxlor extends \Froxlor\Api\ApiCommand
// zum update schritt #1 -> download
if ($isnewerversion == 1) {
$text = 'There is a newer version available: "' . $_version . '" (Your current version is: ' . $this->version . ')';
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'isnewerversion' => $isnewerversion,
'version' => $_version,
'message' => $text,
@@ -83,7 +83,7 @@ class Froxlor extends \Froxlor\Api\ApiCommand
));
} elseif ($isnewerversion == 0) {
// all good
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'isnewerversion' => $isnewerversion,
'version' => $version_label,
'message' => "",
@@ -95,7 +95,7 @@ class Froxlor extends \Froxlor\Api\ApiCommand
}
}
}
return $this->response(300, "successfull", array(
return $this->response(300, "successful", array(
'isnewerversion' => 0,
'version' => $this->version . $this->branding,
'message' => 'Version-check not available due to missing php-curl extension',
@@ -129,7 +129,7 @@ class Froxlor extends \Froxlor\Api\ApiCommand
\Froxlor\System\Cronjob::inserttask('4');
// cron.d file
\Froxlor\System\Cronjob::inserttask('99');
return $this->response(200, "successfull", true);
return $this->response(200, "successful", true);
} catch (\Exception $e) {
throw new \Exception($e->getMessage(), 406);
}
@@ -149,7 +149,7 @@ class Froxlor extends \Froxlor\Api\ApiCommand
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "User " . $this->getUserDetail('loginname') . " exported settings");
$json_export = \Froxlor\SImExporter::export();
return $this->response(200, "successfull", $json_export);
return $this->response(200, "successful", $json_export);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -175,7 +175,7 @@ class Froxlor extends \Froxlor\Api\ApiCommand
'value' => $row['value']
);
}
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
@@ -197,7 +197,7 @@ class Froxlor extends \Froxlor\Api\ApiCommand
{
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
$setting = $this->getParam('key');
return $this->response(200, "successfull", Settings::Get($setting));
return $this->response(200, "successful", Settings::Get($setting));
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -216,7 +216,7 @@ class Froxlor extends \Froxlor\Api\ApiCommand
*/
public function updateSetting()
{
// currently not implemented as it required validation too so no wrong settings are being stored via API
// currently not implemented as it requires validation too so no wrong settings are being stored via API
throw new \Exception("Not available yet.", 501);
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
@@ -227,7 +227,38 @@ class Froxlor extends \Froxlor\Api\ApiCommand
throw new \Exception("Setting '" . $setting . "' could not be found");
}
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] Changing setting '" . $setting . "' from '" . $oldvalue . "' to '" . $value . "'");
return $this->response(200, "successfull", Settings::Set($setting, $value, true));
return $this->response(200, "successful", Settings::Set($setting, $value, true));
}
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* returns a random password based on froxlor settings for min-length, included characters, etc.
*
* @access admin, customer
* @return string
*/
public function generatePassword()
{
return $this->response(200, "successful", \Froxlor\System\Crypt::generatePassword());
}
/**
* can be used to remotely run the integritiy checks froxlor implements
*
* @access admin
* @throws \Exception
* @return string
*/
public function integrityCheck()
{
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
$integrity = new \Froxlor\Database\IntegrityCheck();
$result = $integrity->checkAll();
if ($result) {
return $this->response(200, "successful", "OK");
}
throw new \Exception("Some checks failed.", 406);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -302,7 +333,7 @@ class Froxlor extends \Froxlor\Api\ApiCommand
}
// return the list
return $this->response(200, "successfull", $functions);
return $this->response(200, "successful", $functions);
}
/**

View File

@@ -227,6 +227,10 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
$replace_arr = array(
'SALUTATION' => \Froxlor\User::getCorrectUserSalutation($customer),
'CUST_NAME' => \Froxlor\User::getCorrectUserSalutation($customer), // < keep this for compatibility
'NAME' => $customer['name'],
'FIRSTNAME' => $customer['firstname'],
'COMPANY' => $customer['company'],
'CUSTOMER_NO' => $customer['customernumber'],
'USR_NAME' => $username,
'USR_PASS' => $password,
'USR_PATH' => \Froxlor\FileDir::makeCorrectDir(str_replace($customer['documentroot'], "/", $path))
@@ -264,7 +268,7 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
$result = $this->apiCall('Ftps.get', array(
'username' => $username
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
}
throw new \Exception("No more resources available", 406);
@@ -325,7 +329,7 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get ftp-user '" . $result['username'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
throw new \Exception("FTP user with " . $key . " could not be found", 404);
@@ -335,7 +339,7 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
* update a given ftp-user by id or username
*
* @param int $id
* optional, the customer-id
* optional, the ftp-user-id
* @param string $username
* optional, the username
* @param string $ftp_password
@@ -450,7 +454,7 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
'username' => $result['username']
));
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-user '" . $result['username'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
@@ -460,6 +464,14 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
* optional, admin-only, select ftp-users of a specific customer by id
* @param string $loginname
* optional, admin-only, select ftp-users 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
* @throws \Exception
@@ -469,21 +481,47 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
{
$customer_ids = $this->getAllowedCustomerIds('ftp');
$result = array();
$query_fields = array();
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_FTP_USERS . "`
WHERE `customerid` IN (" . implode(", ", $customer_ids) . ")
");
Database::pexecute($result_stmt, null, true, true);
WHERE `customerid` IN (" . implode(", ", $customer_ids) . ")" . $this->getSearchWhere($query_fields, true) . $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() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list ftp-users");
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* returns the total number of accessable ftp accounts
*
* @param int $customerid
* optional, admin-only, select ftp-users of a specific customer by id
* @param string $loginname
* optional, admin-only, select ftp-users of a specific customer by loginname
*
* @access admin, customer
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
$customer_ids = $this->getAllowedCustomerIds('ftp');
$result = array();
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_ftps FROM `" . TABLE_FTP_USERS . "`
WHERE `customerid` IN (" . implode(", ", $customer_ids) . ")
");
$result = Database::pexecute_first($result_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_ftps']);
}
}
/**
* delete a ftp-user by either id or username
*
@@ -588,6 +626,6 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
Customers::decreaseUsage($customer_data['customerid'], 'ftps_used', $resetaccnumber);
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted ftp-user '" . $result['username'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
}

View File

@@ -25,6 +25,15 @@ class HostingPlans extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
/**
* list all available hosting plans
*
* @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
* @throws \Exception
* @return string json-encoded array count|list
@@ -33,23 +42,51 @@ class HostingPlans extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
{
if ($this->isAdmin()) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list hosting-plans");
$query_fields = array();
$result_stmt = Database::prepare("
SELECT p.*, a.loginname as adminname
FROM `" . TABLE_PANEL_PLANS . "` p, `" . TABLE_PANEL_ADMINS . "` a
WHERE `p`.`adminid` = `a`.`adminid`" . ($this->getUserDetail('customers_see_all') ? '' : " AND `p`.`adminid` = :adminid ") . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
$params = array();
if ($this->getUserDetail('customers_see_all') == '0') {
$params['adminid'] = $this->getUserDetail('adminid');
}
$params = array_merge($params, $query_fields);
Database::pexecute($result_stmt, $params, true, true);
$result = array();
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
}
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* returns the total number of accessable hosting plans
*
* @access admin
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
if ($this->isAdmin()) {
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_plans
FROM `" . TABLE_PANEL_PLANS . "` p, `" . TABLE_PANEL_ADMINS . "` a
WHERE `p`.`adminid` = `a`.`adminid`" . ($this->getUserDetail('customers_see_all') ? '' : " AND `p`.`adminid` = :adminid "));
$params = array();
if ($this->getUserDetail('customers_see_all') == '0') {
$params['adminid'] = $this->getUserDetail('adminid');
}
Database::pexecute($result_stmt, $params);
$result = array();
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_plans']);
}
return $this->response(200, "successfull", array(
'count' => count($result),
'list' => $result
));
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -83,7 +120,7 @@ class HostingPlans extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get hosting-plan '" . $result['name'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
$key = ($id > 0 ? "id #" . $id : "planname '" . $planname . "'");
throw new \Exception("Hosting-plan with " . $key . " could not be found", 404);
@@ -209,7 +246,7 @@ class HostingPlans extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
$result = $this->apiCall('HostingPlans.get', array(
'planname' => $name
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -356,7 +393,7 @@ class HostingPlans extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
);
Database::pexecute($upd_stmt, $update_data, true, true);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] updated hosting-plan '" . $result['name'] . "'");
return $this->response(200, "successfull", $update_data);
return $this->response(200, "successful", $update_data);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -394,7 +431,7 @@ class HostingPlans extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
'id' => $id
), true, true);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted hosting-plan '" . $result['name'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}

View File

@@ -25,6 +25,15 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
/**
* lists all ip/port entries
*
* @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
* @throws \Exception
* @return string json-encoded array count|list
@@ -34,18 +43,20 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
if ($this->isAdmin() && ($this->getUserDetail('change_serversettings') || ! empty($this->getUserDetail('ip')))) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list ips and ports");
$ip_where = "";
$append_where = false;
if (! empty($this->getUserDetail('ip')) && $this->getUserDetail('ip') != - 1) {
$ip_where = "WHERE `id` IN (" . implode(", ", json_decode($this->getUserDetail('ip'), true)) . ")";
$append_where = true;
}
$query_fields = array();
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_IPSANDPORTS . "` " . $ip_where . " ORDER BY `ip` ASC, `port` ASC
");
SELECT * FROM `" . TABLE_PANEL_IPSANDPORTS . "` " . $ip_where . $this->getSearchWhere($query_fields, $append_where) . $this->getOrderBy() . $this->getLimit());
Database::pexecute($result_stmt, null, true, true);
$result = array();
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
}
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
@@ -53,6 +64,30 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* returns the total number of accessable ip/port entries
*
* @access admin
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
if ($this->isAdmin() && ($this->getUserDetail('change_serversettings') || ! empty($this->getUserDetail('ip')))) {
$ip_where = "";
if (! empty($this->getUserDetail('ip')) && $this->getUserDetail('ip') != - 1) {
$ip_where = "WHERE `id` IN (" . implode(", ", json_decode($this->getUserDetail('ip'), true)) . ")";
}
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_ips FROM `" . TABLE_PANEL_IPSANDPORTS . "` " . $ip_where);
$result = Database::pexecute_first($result_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_ips']);
}
}
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* return an ip/port entry by id
*
@@ -81,7 +116,7 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
), true, true);
if ($result) {
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get ip " . $result['ip'] . " " . $result['port']);
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("IP/port with id #" . $id . " could not be found", 404);
}
@@ -135,7 +170,7 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
{
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
$ip = \Froxlor\Validate\Validate::validate_ip2($this->getParam('ip'), false, 'invalidip', false, false, false, false, true);
$ip = \Froxlor\Validate\Validate::validate_ip2($this->getParam('ip'), false, 'invalidip', false, true, false, false, true);
$port = \Froxlor\Validate\Validate::validate($this->getParam('port', true, 80), 'port', '/^(([1-9])|([1-9][0-9])|([1-9][0-9][0-9])|([1-9][0-9][0-9][0-9])|([1-5][0-9][0-9][0-9][0-9])|(6[0-4][0-9][0-9][0-9])|(65[0-4][0-9][0-9])|(655[0-2][0-9])|(6553[0-5]))$/Di', array(
'stringisempty',
'myport'
@@ -220,7 +255,7 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
'port' => $port
));
if ($result_checkfordouble['id'] != '') {
if ($result_checkfordouble && $result_checkfordouble['id'] != '') {
\Froxlor\UI\Response::standard_error('myipnotdouble', '', true);
}
@@ -272,7 +307,7 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$result = $this->apiCall('IpsAndPorts.get', array(
'id' => $ins_data['id']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -332,7 +367,7 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
'id' => $id
));
$ip = \Froxlor\Validate\Validate::validate_ip2($this->getParam('ip', true, $result['ip']), false, 'invalidip', false, false, false, false, true);
$ip = \Froxlor\Validate\Validate::validate_ip2($this->getParam('ip', true, $result['ip']), false, 'invalidip', false, true, false, false, true);
$port = \Froxlor\Validate\Validate::validate($this->getParam('port', true, $result['port']), 'port', '/^(([1-9])|([1-9][0-9])|([1-9][0-9][0-9])|([1-9][0-9][0-9][0-9])|([1-5][0-9][0-9][0-9][0-9])|(6[0-4][0-9][0-9][0-9])|(65[0-4][0-9][0-9])|(655[0-2][0-9])|(6553[0-5]))$/Di', array(
'stringisempty',
'myport'
@@ -427,9 +462,9 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$docroot = '';
}
if ($result['ip'] != $ip && $result['ip'] == Settings::Get('system.ipaddress') && $result_sameipotherport['id'] == '') {
if ($result['ip'] != $ip && $result['ip'] == Settings::Get('system.ipaddress') && $result_sameipotherport == false) {
\Froxlor\UI\Response::standard_error('cantchangesystemip', '', true);
} elseif ($result_checkfordouble['id'] != '' && $result_checkfordouble['id'] != $id) {
} elseif ($result_checkfordouble && $result_checkfordouble['id'] != '' && $result_checkfordouble['id'] != $id) {
\Froxlor\UI\Response::standard_error('myipnotdouble', '', true);
} else {
@@ -479,7 +514,7 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$result = $this->apiCall('IpsAndPorts.get', array(
'id' => $result['id']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
}
throw new \Exception("Not allowed to execute given command.", 403);
@@ -505,7 +540,7 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
));
$result_checkdomain_stmt = Database::prepare("
SELECT `id_domain` as `id` FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_ipandports` = :id
SELECT `id_domain` FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_ipandports` = :id
");
$result_checkdomain = Database::pexecute_first($result_checkdomain_stmt, array(
'id' => $id
@@ -525,7 +560,7 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
'ip' => $result['ip']
));
if (($result['ip'] != Settings::Get('system.ipaddress')) || ($result['ip'] == Settings::Get('system.ipaddress') && $result_sameipotherport['id'] != '')) {
if (($result['ip'] != Settings::Get('system.ipaddress')) || ($result['ip'] == Settings::Get('system.ipaddress') && $result_sameipotherport != false)) {
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_IPSANDPORTS . "`
@@ -548,7 +583,7 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
\Froxlor\System\Cronjob::inserttask('4');
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted IP/port '" . $result['ip'] . ":" . $result['port'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
} else {
\Froxlor\UI\Response::standard_error('cantdeletesystemip', '', true);
}

View File

@@ -34,7 +34,9 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
* @param bool $sendinfomail
* optional, send created resource-information to customer, default: false
* @param int $customerid
* required when called as admin, not needed when called as customer
* optional, admin-only, the customer-id
* @param string $loginname
* optional, admin-only, the loginname
*
* @access admin, customer
* @throws \Exception
@@ -42,8 +44,6 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
*/
public function add()
{
if ($this->getUserDetail('mysqls_used') < $this->getUserDetail('mysqls') || $this->getUserDetail('mysqls') == '-1') {
// required paramters
$password = $this->getParam('mysql_password');
@@ -51,6 +51,8 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$dbserver = $this->getParam('mysql_server', true, 0);
$databasedescription = $this->getParam('description', true, '');
$sendinfomail = $this->getBoolParam('sendinfomail', true, 0);
// get needed customer info to reduce the mysql-usage-counter by one
$customer = $this->getCustomerData('mysqls');
// validation
$password = \Froxlor\Validate\Validate::validate($password, 'password', '', '', array(), true);
@@ -71,9 +73,6 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$sendinfomail = 0;
}
// get needed customer info to reduce the mysql-usage-counter by one
$customer = $this->getCustomerData('mysqls');
$newdb_params = array(
'loginname' => ($this->isAdmin() ? $customer['loginname'] : $this->getUserDetail('loginname')),
'mysql_lastaccountnumber' => ($this->isAdmin() ? $customer['mysql_lastaccountnumber'] : $this->getUserDetail('mysql_lastaccountnumber'))
@@ -126,6 +125,10 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$replace_arr = array(
'SALUTATION' => \Froxlor\User::getCorrectUserSalutation($userinfo),
'CUST_NAME' => \Froxlor\User::getCorrectUserSalutation($userinfo), // < keep this for compatibility
'NAME' => $userinfo['name'],
'FIRSTNAME' => $userinfo['firstname'],
'COMPANY' => $userinfo['company'],
'CUSTOMER_NO' => $userinfo['customernumber'],
'DB_NAME' => $username,
'DB_PASS' => $password,
'DB_DESC' => $databasedescription,
@@ -166,9 +169,7 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result = $this->apiCall('Mysqls.get', array(
'dbname' => $username
));
return $this->response(200, "successfull", $result);
}
throw new \Exception("No more resources available", 406);
return $this->response(200, "successful", $result);
}
/**
@@ -255,9 +256,9 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
), true, true);
$mbdata = $mbdata_stmt->fetch(\PDO::FETCH_ASSOC);
Database::needRoot(false);
$result['size'] = $mbdata['MB'];
$result['size'] = $mbdata['MB'] ?? 0;
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get database '" . $result['databasename'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
$key = ($id > 0 ? "id #" . $id : "dbname '" . $dbname . "'");
throw new \Exception("MySQL database with " . $key . " could not be found", 404);
@@ -276,6 +277,10 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
* optional, update password for the database
* @param string $description
* optional, description for database
* @param int $customerid
* optional, admin-only, the customer-id
* @param string $loginname
* optional, admin-only, the loginname
*
* @access admin, customer
* @throws \Exception
@@ -287,6 +292,7 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$dn_optional = ($id <= 0 ? false : true);
$dbname = $this->getParam('dbname', $dn_optional, '');
$dbserver = $this->getParam('mysql_server', true, - 1);
$customer = $this->getCustomerData();
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'mysql')) {
throw new \Exception("You cannot access this resource", 405);
@@ -307,9 +313,6 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$password = \Froxlor\Validate\Validate::validate($password, 'password', '', '', array(), true);
$databasedescription = \Froxlor\Validate\Validate::validate(trim($databasedescription), 'description', '', '', array(), true);
// get needed customer info to reduce the mysql-usage-counter by one
$customer = $this->getCustomerData();
if ($password != '') {
// validate password
$password = \Froxlor\System\Crypt::validatePassword($password, true);
@@ -347,7 +350,7 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result = $this->apiCall('Mysqls.get', array(
'dbname' => $result['databasename']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
@@ -359,6 +362,14 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
* optional, admin-only, select dbs of a specific customer by id
* @param string $loginname
* optional, admin-only, select dbs 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
* @throws \Exception
@@ -369,10 +380,10 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result = array();
$dbserver = $this->getParam('mysql_server', true, - 1);
$customer_ids = $this->getAllowedCustomerIds('mysql');
$query_fields = array();
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_DATABASES . "`
WHERE `customerid`= :customerid AND `dbserver` = :dbserver
");
WHERE `customerid`= :customerid AND `dbserver` = :dbserver" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
if ($dbserver < 0) {
// use all dbservers
$dbservers_stmt = Database::query("SELECT DISTINCT `dbserver` FROM `" . TABLE_PANEL_DATABASES . "`");
@@ -388,10 +399,10 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
foreach ($customer_ids as $customer_id) {
foreach ($dbservers as $_dbserver) {
Database::pexecute($result_stmt, array(
Database::pexecute($result_stmt, array_merge(array(
'customerid' => $customer_id,
'dbserver' => $_dbserver['dbserver']
), true, true);
), $query_fields), true, true);
// Begin root-session
Database::needRoot(true, $_dbserver['dbserver']);
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
@@ -404,18 +415,43 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
"table_schema" => $row['databasename']
), true, true);
$mbdata = $mbdata_stmt->fetch(\PDO::FETCH_ASSOC);
$row['size'] = $mbdata['MB'];
$row['size'] = $mbdata['MB'] ?? 0;
$result[] = $row;
}
Database::needRoot(false);
}
}
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* returns the total number of accessable databases
*
* @param int $customerid
* optional, admin-only, select dbs of a specific customer by id
* @param string $loginname
* optional, admin-only, select dbs of a specific customer by loginname
*
* @access admin, customer
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
$customer_ids = $this->getAllowedCustomerIds('mysql');
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_dbs FROM `" . TABLE_PANEL_DATABASES . "`
WHERE `customerid` IN (" . implode(", ", $customer_ids) . ")
");
$result = Database::pexecute_first($result_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_dbs']);
}
}
/**
* delete a mysql database by either id or dbname
*
@@ -425,6 +461,10 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
* optional, the databasename
* @param int $mysql_server
* optional, specify database-server, default is none
* @param int $customerid
* optional, admin-only, the customer-id
* @param string $loginname
* optional, admin-only, the loginname
*
* @access admin, customer
* @throws \Exception
@@ -436,6 +476,7 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$dn_optional = ($id <= 0 ? false : true);
$dbname = $this->getParam('dbname', $dn_optional, '');
$dbserver = $this->getParam('mysql_server', true, - 1);
$customer = $this->getCustomerData();
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'mysql')) {
throw new \Exception("You cannot access this resource", 405);
@@ -462,7 +503,6 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
), true, true);
// get needed customer info to reduce the mysql-usage-counter by one
$customer = $this->getCustomerData();
$mysql_used = $customer['mysqls_used'];
// reduce mysql-usage-counter
@@ -470,6 +510,6 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
Customers::decreaseUsage($customer['customerid'], 'mysqls_used', $resetaccnumber);
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted database '" . $result['databasename'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
}

View File

@@ -27,6 +27,14 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
*
* @param bool $with_subdomains
* optional, also include subdomains to the list domains that use the config, default 0 (false)
* @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
* @throws \Exception
@@ -38,16 +46,14 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list php-configs");
$with_subdomains = $this->getBoolParam('with_subdomains', true, false);
$result = Database::query("
$query_fields = array();
$result_stmt = Database::prepare("
SELECT c.*, fd.description as fpmdesc
FROM `" . TABLE_PANEL_PHPCONFIGS . "` c
LEFT JOIN `" . TABLE_PANEL_FPMDAEMONS . "` fd ON fd.id = c.fpmsettingid
ORDER BY c.description ASC
");
LEFT JOIN `" . TABLE_PANEL_FPMDAEMONS . "` fd ON fd.id = c.fpmsettingid" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
Database::pexecute($result_stmt, $query_fields, true, true);
$phpconfigs = array();
while ($row = $result->fetch(\PDO::FETCH_ASSOC)) {
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$query_params = array(
'id' => $row['id']
);
@@ -107,7 +113,7 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$phpconfigs[] = $row;
}
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($phpconfigs),
'list' => $phpconfigs
));
@@ -115,6 +121,28 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* returns the total number of accessable php-setting entries
*
* @access admin
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
if ($this->isAdmin()) {
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_phps
FROM `" . TABLE_PANEL_PHPCONFIGS . "` c
");
$result = Database::pexecute_first($result_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_phps']);
}
}
throw new \Exception("Not allowed to execute given command.", 403);
}
/**
* return a php-setting entry by id
*
@@ -137,7 +165,7 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
'id' => $id
), true, true);
if ($result) {
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("php-config with id #" . $id . " could not be found", 404);
}
@@ -339,7 +367,7 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$result = $this->apiCall('PhpSettings.get', array(
'id' => $ins_data['id']
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -535,7 +563,7 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$result = $this->apiCall('PhpSettings.get', array(
'id' => $id
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
@@ -586,7 +614,7 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
\Froxlor\System\Cronjob::inserttask('1');
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);
}

View File

@@ -41,6 +41,8 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
* optional, php-settings-id, if empty the $domain value is used
* @param int $redirectcode
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
* @param bool $sslenabled
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default 1 (true)
* @param bool $ssl_redirect
* optional, whether to generate a https-redirect or not, default false; requires SSL to be enabled
* @param bool $letsencrypt
@@ -76,6 +78,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
$isemaildomain = $this->getParam('isemaildomain', true, 0);
if (Settings::Get('system.use_ssl')) {
$sslenabled = $this->getBoolParam('sslenabled', true, 1);
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, 0);
$letsencrypt = $this->getBoolParam('letsencrypt', true, 0);
$http2 = $this->getBoolParam('http2', true, 0);
@@ -83,6 +86,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$hsts_sub = $this->getBoolParam('hsts_sub', true, 0);
$hsts_preload = $this->getBoolParam('hsts_preload', true, 0);
} else {
$sslenabled = 0;
$ssl_redirect = 0;
$letsencrypt = 0;
$http2 = 0;
@@ -95,6 +99,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$customer = $this->getCustomerData('subdomains');
// validation
$subdomain = strtolower($subdomain);
if (substr($subdomain, 0, 4) == 'xn--') {
\Froxlor\UI\Response::standard_error('domain_nopunycode', '', true);
}
@@ -114,7 +119,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
'mydomain'
), '', true);
}
if ($completedomain == Settings::Get('system.hostname')) {
if ($completedomain == strtolower(Settings::Get('system.hostname'))) {
\Froxlor\UI\Response::standard_error('admin_domain_emailsystemhostname', '', true);
}
@@ -190,7 +195,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
} elseif ($subdomain == 'www' && $domain_check['wwwserveralias'] == '1') {
// you cannot add 'www' as subdomain when the maindomain generates a www-alias
\Froxlor\UI\Response::standard_error('wwwnotallowed', '', true);
} elseif (strtolower($completedomain_check['domain']) == strtolower($completedomain)) {
} elseif ($completedomain_check && strtolower($completedomain_check['domain']) == strtolower($completedomain)) {
// the domain does already exist as main-domain
\Froxlor\UI\Response::standard_error('domainexistalready', $completedomain, true);
}
@@ -251,6 +256,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
`customerid` = :customerid,
`adminid` = :adminid,
`domain` = :domain,
`domain_ace` = :domain_ace,
`documentroot` = :documentroot,
`aliasdomain` = :aliasdomain,
`parentdomainid` = :parentdomainid,
@@ -275,12 +281,14 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
`override_tls` = :override_tls,
`ssl_protocols` = :ssl_protocols,
`ssl_cipher_list` = :ssl_cipher_list,
`tlsv13_cipher_list` = :tlsv13_cipher_list
`tlsv13_cipher_list` = :tlsv13_cipher_list,
`ssl_enabled` = :sslenabled
");
$params = array(
"customerid" => $customer['customerid'],
"adminid" => $customer['adminid'],
"domain" => $completedomain,
"domain_ace" => $idna_convert->decode($completedomain),
"documentroot" => $path,
"aliasdomain" => $aliasdomain != 0 ? $aliasdomain : null,
"parentdomainid" => $domain_check['id'],
@@ -305,7 +313,8 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
"override_tls" => $domain_check['override_tls'],
"ssl_protocols" => $domain_check['ssl_protocols'],
"ssl_cipher_list" => $domain_check['ssl_cipher_list'],
"tlsv13_cipher_list" => $domain_check['tlsv13_cipher_list']
"tlsv13_cipher_list" => $domain_check['tlsv13_cipher_list'],
"sslenabled" => $sslenabled
);
Database::pexecute($stmt, $params, true, true);
$subdomain_id = Database::lastInsertId();
@@ -336,7 +345,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$result = $this->apiCall('SubDomains.get', array(
'id' => $subdomain_id
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
throw new \Exception("No more resources available", 406);
}
@@ -400,7 +409,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
);
}
} else {
if (Settings::IsInList('panel.customer_hide_options', 'domains')) {
if (! $this->isInternal() && Settings::IsInList('panel.customer_hide_options', 'domains')) {
throw new \Exception("You cannot access this resource", 405);
}
$result_stmt = Database::prepare("
@@ -417,7 +426,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get subdomain '" . $result['domain'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
throw new \Exception("Subdomain with " . $key . " could not be found", 404);
@@ -446,6 +455,8 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
* optional, php-settings-id, if empty the $domain value is used
* @param int $redirectcode
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
* @param bool $sslenabled
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default 1 (true)
* @param bool $ssl_redirect
* optional, whether to generate a https-redirect or not, default false; requires SSL to be enabled
* @param bool $letsencrypt
@@ -493,6 +504,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
$redirectcode = $this->getParam('redirectcode', true, \Froxlor\Domain\Domain::getDomainRedirectId($id));
if (Settings::Get('system.use_ssl')) {
$sslenabled = $this->getBoolParam('sslenabled', true, $result['ssl_enabled']);
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, $result['ssl_redirect']);
$letsencrypt = $this->getBoolParam('letsencrypt', true, $result['letsencrypt']);
$http2 = $this->getBoolParam('http2', true, $result['http2']);
@@ -500,6 +512,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$hsts_sub = $this->getBoolParam('hsts_sub', true, $result['hsts_sub']);
$hsts_preload = $this->getBoolParam('hsts_preload', true, $result['hsts_preload']);
} else {
$sslenabled = 0;
$ssl_redirect = 0;
$letsencrypt = 0;
$http2 = 0;
@@ -616,6 +629,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
`iswildcarddomain` = :iswildcarddomain,
`aliasdomain` = :aliasdomain,
`openbasedir_path` = :openbasedir_path,
`ssl_enabled` = :sslenabled,
`ssl_redirect` = :ssl_redirect,
`letsencrypt` = :letsencrypt,
`http2` = :http2,
@@ -632,6 +646,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
"iswildcarddomain" => $iswildcarddomain,
"aliasdomain" => ($aliasdomain != 0 && $alias_check == 0) ? $aliasdomain : null,
"openbasedir_path" => $openbasedir_path,
"sslenabled" => $sslenabled,
"ssl_redirect" => $ssl_redirect,
"letsencrypt" => $letsencrypt,
"http2" => $http2,
@@ -668,6 +683,8 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
Database::pexecute($del_stmt, array(
'id' => $id
), true, true);
// remove domain from acme.sh / lets encrypt if used
\Froxlor\System\Cronjob::inserttask('12', $result['domain']);
}
\Froxlor\System\Cronjob::inserttask('1');
@@ -678,12 +695,25 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$result = $this->apiCall('SubDomains.get', array(
'id' => $id
));
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**
* lists all subdomain entries
*
* @param int $customerid
* optional, admin-only, select (sub)domains of a specific customer by id
* @param string $loginname
* optional, admin-only, select (sub)domains 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
* @throws \Exception
* @return string json-encoded array count|list
@@ -696,6 +726,105 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$customerid = $this->getParam('customerid', true, 0);
$loginname = $this->getParam('loginname', true, '');
if (! empty($customerid) || ! empty($loginname)) {
$result = $this->apiCall('Customers.get', array(
'id' => $customerid,
'loginname' => $loginname
));
$custom_list_result = array(
$result
);
} else {
$_custom_list_result = $this->apiCall('Customers.listing');
$custom_list_result = $_custom_list_result['list'];
}
$customer_ids = array();
$customer_stdsubs = array();
foreach ($custom_list_result as $customer) {
$customer_ids[] = $customer['customerid'];
$customer_stdsubs[$customer['customerid']] = $customer['standardsubdomain'];
}
if (empty($customer_ids)) {
throw new \Exception("Required resource unsatisfied.", 405);
}
if (empty($customer_stdsubs)) {
throw new \Exception("Required resource unsatisfied.", 405);
}
$select_fields = [
'`d`.*'
];
} else {
if (Settings::IsInList('panel.customer_hide_options', 'domains')) {
throw new \Exception("You cannot access this resource", 405);
}
$customer_ids = array(
$this->getUserDetail('customerid')
);
$customer_stdsubs = array(
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
);
$select_fields = [
'`d`.`id`',
'`d`.`customerid`',
'`d`.`domain`',
'`d`.`domain_ace`',
'`d`.`documentroot`',
'`d`.`isbinddomain`',
'`d`.`isemaildomain`',
'`d`.`caneditdomain`',
'`d`.`iswildcarddomain`',
'`d`.`parentdomainid`',
'`d`.`letsencrypt`',
'`d`.`registration_date`',
'`d`.`termination_date`'
];
}
$query_fields = array();
// prepare select statement
$domains_stmt = Database::prepare("
SELECT " . implode(",", $select_fields) . ", IF(`d`.`parentdomainid` > 0, `pd`.`domain_ace`, `d`.`domain_ace`) AS `parentdomainname`, `ad`.`id` AS `aliasdomainid`, `ad`.`domain` AS `aliasdomain`, `da`.`id` AS `domainaliasid`, `da`.`domain` AS `domainalias`
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `ad` ON `d`.`aliasdomain`=`ad`.`id`
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `da` ON `da`.`aliasdomain`=`d`.`id`
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON `pd`.`id`=`d`.`parentdomainid`
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
AND `d`.`email_only` = '0'
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` " . $this->getOrderBy(true) . $this->getLimit());
$result = array();
Database::pexecute($domains_stmt, $query_fields, true, true);
while ($row = $domains_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
}
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* returns the total number of accessable subdomain entries
*
* @param int $customerid
* optional, admin-only, select (sub)domains of a specific customer by id
* @param string $loginname
* optional, admin-only, select (sub)domains of a specific customer by loginname
*
* @access admin, customer
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
if ($this->isAdmin()) {
// if we're an admin, list all databases of all the admins customers
// or optionally for one specific customer identified by id or loginname
$customerid = $this->getParam('customerid', true, 0);
$loginname = $this->getParam('loginname', true, '');
if (! empty($customerid) || ! empty($loginname)) {
$result = $this->apiCall('Customers.get', array(
'id' => $customerid,
@@ -725,33 +854,19 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
);
}
// prepare select statement
$domains_stmt = Database::prepare("
SELECT `d`.`id`, `d`.`customerid`, `d`.`domain`, `d`.`documentroot`, `d`.`isbinddomain`, `d`.`isemaildomain`, `d`.`caneditdomain`, `d`.`iswildcarddomain`, `d`.`parentdomainid`, `d`.`letsencrypt`, `d`.`termination_date`, `ad`.`id` AS `aliasdomainid`, `ad`.`domain` AS `aliasdomain`, `da`.`id` AS `domainaliasid`, `da`.`domain` AS `domainalias`
SELECT COUNT(*) as num_subdom
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `ad` ON `d`.`aliasdomain`=`ad`.`id`
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `da` ON `da`.`aliasdomain`=`d`.`id`
WHERE `d`.`customerid`= :customerid
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
AND `d`.`email_only` = '0'
AND `d`.`id` <> :standardsubdomain
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")
");
$result = array();
foreach ($customer_ids as $customer_id) {
Database::pexecute($domains_stmt, array(
"customerid" => $customer_id,
"standardsubdomain" => $customer_stdsubs[$customer_id]
), true, true);
while ($row = $domains_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
$result = Database::pexecute_first($domains_stmt, null, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_subdom']);
}
}
return $this->response(200, "successfull", array(
'count' => count($result),
'list' => $result
));
}
/**
* delete a subdomain by either id or domainname
@@ -760,6 +875,8 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
* optional, the domain-id
* @param string $domainname
* optional, the domainname
* @param int $customerid
* required when called as admin, not needed when called as customer
*
* @access admin, customer
* @throws \Exception
@@ -863,7 +980,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
Customers::decreaseUsage($customer['customerid'], 'subdomains_used');
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted subdomain '" . $result['domain'] . "'");
return $this->response(200, "successfull", $result);
return $this->response(200, "successful", $result);
}
/**

View File

@@ -0,0 +1,211 @@
<?php
namespace Froxlor\Api\Commands;
use Froxlor\Database\Database;
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* For the full copyright and license information, please view the COPYING
* file that was distributed with this source code. You can also view the
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
*
* @copyright (c) the authors
* @author Froxlor team <team@froxlor.org> (2010-)
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
* @package API
* @since 0.10.6
*
*/
class SysLog extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntity
{
/**
* list all log-entries
*
* @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
* @throws \Exception
* @return string json-encoded array count|list
*/
public function listing()
{
$result = array();
$query_fields = array();
if ($this->isAdmin() && $this->getUserDetail('customers_see_all') == '1') {
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_LOG . "` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
} elseif ($this->isAdmin()) {
// get all admin customers
$_custom_list_result = $this->apiCall('Customers.listing');
$custom_list_result = $_custom_list_result['list'];
$customer_names = array();
foreach ($custom_list_result as $customer) {
$customer_names[] = $customer['loginname'];
}
if (count($customer_names) > 0) {
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_LOG . "`
WHERE `user` = :loginname OR `user` IN ('" . implode("', '", $customer_names) . "')" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
} else {
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_LOG . "`
WHERE `user` = :loginname" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
}
$query_fields['loginname'] = $this->getUserDetail('loginname');
} else {
// every one else just sees their logs
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_LOG . "`
WHERE `user` = :loginname AND `action` <> 99 " . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
$query_fields['loginname'] = $this->getUserDetail('loginname');
}
Database::pexecute($result_stmt, $query_fields, true, true);
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list log-entries");
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* returns the total number of log-entries
*
* @access admin
* @throws \Exception
* @return string json-encoded array
*/
public function listingCount()
{
$params = null;
if ($this->isAdmin() && $this->getUserDetail('customers_see_all') == '1') {
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_logs FROM `" . TABLE_PANEL_LOG . "`
");
} elseif ($this->isAdmin()) {
// get all admin customers
$_custom_list_result = $this->apiCall('Customers.listing');
$custom_list_result = $_custom_list_result['list'];
$customer_names = array();
foreach ($custom_list_result as $customer) {
$customer_names[] = $customer['loginname'];
}
if (count($customer_names) > 0) {
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_logs FROM `" . TABLE_PANEL_LOG . "`
WHERE `user` = :loginname OR `user` IN ('" . implode("', '", $customer_names) . "')
");
} else {
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_logs FROM `" . TABLE_PANEL_LOG . "`
WHERE `user` = :loginname
");
}
$params = [
'loginname' => $this->getUserDetail('loginname')
];
} else {
// every one else just sees their logs
$result_stmt = Database::prepare("
SELECT COUNT(*) as num_logs FROM `" . TABLE_PANEL_LOG . "`
WHERE `user` = :loginname AND `action` <> 99
");
$params = [
'loginname' => $this->getUserDetail('loginname')
];
}
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
return $this->response(200, "successful", $result['num_logs']);
}
}
/**
* You cannot get log entries
*/
public function get()
{
throw new \Exception('You cannot get log entries', 303);
}
/**
* You cannot add log entries
*/
public function add()
{
throw new \Exception('You cannot add log entries', 303);
}
/**
* You cannot update log entries
*/
public function update()
{
throw new \Exception('You cannot update log entries', 303);
}
/**
* delete log entries
*
* @param int $min_to_keep
* optional minutes to keep, default is 10
*
* @access admin
* @throws \Exception
* @return string json-encoded array
*/
public function delete()
{
if ($this->isAdmin()) {
$min_to_keep = self::getParam('min_to_keep', true, 10);
if ($min_to_keep < 0) {
$min_to_keep = 0;
}
$truncatedate = time() - (60 * $min_to_keep);
$params = array();
if ($this->getUserDetail('customers_see_all') == '1') {
$result_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_LOG . "` WHERE `date` < :trunc
");
} else {
// get all admin customers
$_custom_list_result = $this->apiCall('Customers.listing');
$custom_list_result = $_custom_list_result['list'];
$customer_names = array();
foreach ($custom_list_result as $customer) {
$customer_names[] = $customer['loginname'];
}
if (count($customer_names) > 0) {
$result_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_LOG . "` WHERE `date` < :trunc AND `user` = :loginname OR `user` IN ('" . implode("', '", $customer_names) . "')
");
} else {
$result_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_LOG . "` WHERE `date` < :trunc AND `user` = :loginname
");
}
$params = [
'loginname' => $this->getUserDetail('loginname')
];
}
$params['trunc'] = $truncatedate;
Database::pexecute($result_stmt, $params, true, true);
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] truncated the froxlor syslog");
return $this->response(200, "successful", true);
}
throw new \Exception("Not allowed to execute given command.", 403);
}
}

View File

@@ -110,12 +110,22 @@ class Traffic extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list traffic");
return $this->response(200, "successfull", array(
return $this->response(200, "successful", array(
'count' => count($result),
'list' => $result
));
}
/**
* You cannot count the traffic data list
*
* @throws \Exception
*/
public function listingCount()
{
throw new \Exception('You cannot count the traffic data list', 303);
}
/**
* You cannot delete traffic data
*

View File

@@ -56,7 +56,7 @@ class FroxlorRPC
private static function validateAuth($key, $secret)
{
$sel_stmt = \Froxlor\Database\Database::prepare("
SELECT ak.*, a.api_allowed as admin_api_allowed, c.api_allowed as cust_api_allowed
SELECT ak.*, a.api_allowed as admin_api_allowed, c.api_allowed as cust_api_allowed, c.deactivated
FROM `api_keys` ak
LEFT JOIN `panel_admins` a ON a.adminid = ak.adminid
LEFT JOIN `panel_customers` c ON c.customerid = ak.customerid
@@ -67,7 +67,7 @@ class FroxlorRPC
'as' => $secret
), true, true);
if ($result) {
if ($result['apikey'] == $key && $result['secret'] == $secret && ($result['valid_until'] == - 1 || $result['valid_until'] >= time()) && (($result['customerid'] == 0 && $result['admin_api_allowed'] == 1) || ($result['customerid'] > 0 && $result['cust_api_allowed'] == 1))) {
if ($result['apikey'] == $key && $result['secret'] == $secret && ($result['valid_until'] == - 1 || $result['valid_until'] >= time()) && (($result['customerid'] == 0 && $result['admin_api_allowed'] == 1) || ($result['customerid'] > 0 && $result['cust_api_allowed'] == 1 && $result['deactivated'] == 0))) {
// get user to check whether api call is allowed
if (! empty($result['allowed_from'])) {
// @todo allow specification and validating of whole subnets later

View File

@@ -21,6 +21,8 @@ interface ResourceEntity
public function listing();
public function listingCount();
public function get();
public function add();

View File

@@ -26,11 +26,16 @@ class ConfigServicesAction extends \Froxlor\Cli\Action
*/
private function validate()
{
global $lng;
$this->checkConfigParam(true);
$this->parseConfig();
require FROXLOR_INSTALL_DIR . '/lib/tables.inc.php';
include_once FROXLOR_INSTALL_DIR . '/lng/english.lng.php';
include_once FROXLOR_INSTALL_DIR . '/lng/lng_references.php';
if (array_key_exists("import-settings", $this->_args)) {
$this->importSettings();
}
@@ -78,6 +83,20 @@ class ConfigServicesAction extends \Froxlor\Cli\Action
$distros = glob($config_dir . '*.xml');
// tmp array
$distributions_select_data = array();
//set default os.
$os_dist = array('ID' => 'buster');
$os_version = array('0' => '10');
$os_default = $os_dist['ID'];
//read os-release
if(file_exists('/etc/os-release')) {
$os_dist = parse_ini_file('/etc/os-release', false);
if(is_array($os_dist) && array_key_exists('ID', $os_dist) && array_key_exists('VERSION_ID', $os_dist)) {
$os_version = explode('.',$os_dist['VERSION_ID'])[0];
}
}
// read in all the distros
foreach ($distros as $_distribution) {
// get configparser object
@@ -86,6 +105,12 @@ class ConfigServicesAction extends \Froxlor\Cli\Action
$dist_display = $this->getCompleteDistroName($dist);
// store in tmp array
$distributions_select_data[$dist_display] = str_replace(".xml", "", strtolower(basename($_distribution)));
//guess if this is the current distro.
$ver = explode('.', $dist->distributionVersion)[0];
if (strtolower($os_dist['ID']) == strtolower($dist->distributionName) && $os_version == $ver) {
$os_default = str_replace(".xml", "", strtolower(basename($_distribution)));
}
}
// sort by distribution name
@@ -103,7 +128,7 @@ class ConfigServicesAction extends \Froxlor\Cli\Action
echo PHP_EOL;
while (! in_array($_daemons_config['distro'], $distributions_select_data)) {
$_daemons_config['distro'] = ConfigServicesCmd::getInput("choose distribution", "buster");
$_daemons_config['distro'] = ConfigServicesCmd::getInput("choose distribution", $os_default);
}
// go through all services and let user check whether to include it or not

View File

@@ -435,11 +435,7 @@ class ConfigDaemon
}
return '';
} elseif (preg_match('/^const\.(.*)$/', $matches[1], $match)) {
if (defined($match[1])) {
return constant($match[1]);
} else {
return '';
}
return $this->returnDynamic($match[1]);
} elseif (preg_match('/^sql\.(.*)$/', $matches[1], $match)) {
if (is_null($this->sqldata_cache)) {
// read in sql-data (if exists)
@@ -455,6 +451,14 @@ class ConfigDaemon
return $content;
}
private function returnDynamic($key = null)
{
$dynamics = [
'install_dir' => \Froxlor\Froxlor::getInstallDir()
];
return $dynamics[$key] ?? '';
}
/**
* Check if visibility should be changed
*

View File

@@ -39,6 +39,13 @@ class ConfigParser
*/
private $services = array();
/**
* Holding the available defaults in the XML
*
* @var array
*/
private $defaults = array();
/**
* Store the parsed SimpleXMLElement for usage
*
@@ -147,7 +154,7 @@ class ConfigParser
*
* @return bool
*/
private function parse()
private function parseServices()
{
// We only want to parse the stuff one time
if ($this->isparsed == true) {
@@ -174,6 +181,29 @@ class ConfigParser
return true;
}
/**
* Parse the XML and populate $this->services
*
* @return bool
*/
private function parseDefaults()
{
// We only want to parse the stuff one time
if ($this->isparsed == true) {
return true;
}
// Get all defaults
$defaults = $this->xml->xpath('//defaults');
foreach ($defaults as $default) {
$this->defaults = $default;
}
// Switch flag to indicate we parsed our data
$this->isparsed = true;
return true;
}
/**
* Return all services defined by the XML
*
@@ -184,9 +214,25 @@ class ConfigParser
public function getServices()
{
// Let's parse this shit(!)
$this->parse();
$this->parseServices();
// Return our carefully searched for services
return $this->services;
}
/**
* Return all defaults defined by the XML
*
* The array will hold ConfigDefaults - Objects for further handling
*
* @return array
*/
public function getDefaults()
{
// Let's parse this shit(!)
$this->parseDefaults();
// Return our carefully searched for defaults
return $this->defaults;
}
}

View File

@@ -99,7 +99,7 @@ class CronConfig
$binpath = Settings::Get("system.croncmdline");
// fallback as it is important
if ($binpath === null) {
$binpath = "/usr/bin/nice -n 5 /usr/bin/php5 -q";
$binpath = "/usr/bin/nice -n 5 /usr/bin/php -q";
}
$cronfile .= "root " . $binpath . " " . \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . "/scripts/froxlor_master_cronjob.php") . " --" . $row_cronentry['cronfile'] . " 1> /dev/null\n";

View File

@@ -112,10 +112,13 @@ class Bind extends DnsBase
if (count($this->ns) > 0) {
foreach ($this->ns as $ns) {
foreach ($ns["ips"] as $ip) {
$ip = \Froxlor\Validate\Validate::validate_ip2($ip, true, 'invalidip', true, true, true);
if ($ip) {
$bindconf_file .= ' ' . $ip . ";\n";
}
}
}
}
// AXFR server #100
if (count($this->axfr) > 0) {
foreach ($this->axfr as $axfrserver) {

View File

@@ -172,7 +172,7 @@ class Apache extends HttpConfigBase
$mypath = $this->getMyPath($row_ipsandports);
$this->virtualhosts_data[$vhosts_filename] .= 'DocumentRoot "' . $mypath . '"' . "\n";
$this->virtualhosts_data[$vhosts_filename] .= 'DocumentRoot "' . rtrim($mypath, "/") . '"' . "\n";
if ($row_ipsandports['vhostcontainer_servername_statement'] == '1') {
$this->virtualhosts_data[$vhosts_filename] .= ' ServerName ' . Settings::Get('system.hostname') . "\n";
@@ -442,7 +442,9 @@ class Apache extends HttpConfigBase
'loginname' => 'froxlor.panel',
'documentroot' => $mypath,
'customerroot' => $mypath,
'parentdomainid' => 0
'parentdomainid' => 0,
'ssl_honorcipherorder' => Settings::Get('system.honorcipherorder'),
'ssl_sessiontickets' => Settings::Get('system.sessiontickets')
);
// override corresponding array values
@@ -478,9 +480,12 @@ class Apache extends HttpConfigBase
$this->virtualhosts_data[$vhosts_filename] .= ' SSLOpenSSLConfCmd DHParameters "' . $dhparams . '"' . "\n";
}
$this->virtualhosts_data[$vhosts_filename] .= ' SSLCompression Off' . "\n";
if (Settings::Get('system.sessionticketsenabled') == '1') {
$this->virtualhosts_data[$vhosts_filename] .= ' SSLSessionTickets ' . ($domain['ssl_sessiontickets'] == '1' ? 'on' : 'off') . "\n";
}
// this makes it more secure, thx to Marcel (08/2013)
$this->virtualhosts_data[$vhosts_filename] .= ' SSLHonorCipherOrder On' . "\n";
}
$this->virtualhosts_data[$vhosts_filename] .= ' SSLHonorCipherOrder ' . ($domain['ssl_honorcipherorder'] == '1' ? 'on' : 'off') . "\n";
$this->virtualhosts_data[$vhosts_filename] .= ' SSLCipherSuite ' . Settings::Get('system.ssl_cipher_list') . "\n";
$protocols = array_map('trim', explode(",", Settings::Get('system.ssl_protocols')));
if (in_array("TLSv1.3", $protocols) && ! empty(Settings::Get('system.tlsv13_cipher_list')) && Settings::Get('system.apache24') == 1) {
@@ -656,7 +661,7 @@ class Apache extends HttpConfigBase
if ($domain['deactivated'] == '1' && Settings::Get('system.deactivateddocroot') != '') {
$webroot_text .= ' # Using docroot for deactivated users...' . "\n";
$webroot_text .= ' DocumentRoot "' . \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')) . "\"\n";
$webroot_text .= ' DocumentRoot "' . rtrim(\Froxlor\FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')), "/") . "\"\n";
$webroot_text .= ' <Directory "' . \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.deactivateddocroot')) . '">' . "\n";
// >=apache-2.4 enabled?
if (Settings::Get('system.apache24') == '1') {
@@ -669,7 +674,7 @@ class Apache extends HttpConfigBase
$webroot_text .= ' </Directory>' . "\n";
$this->deactivated = true;
} else {
$webroot_text .= ' DocumentRoot "' . $domain['documentroot'] . "\"\n";
$webroot_text .= ' DocumentRoot "' . rtrim($domain['documentroot'], "/") . "\"\n";
$this->deactivated = false;
}
@@ -755,7 +760,7 @@ class Apache extends HttpConfigBase
$logtype = 'combined';
if (Settings::Get('system.logfiles_format') != '') {
$logtype = 'frx_custom';
$logfiles_text .= ' LogFormat "' . Settings::Get('system.logfiles_format') . '" ' . $logtype . "\n";
$logfiles_text .= ' LogFormat ' . Settings::Get('system.logfiles_format') . ' ' . $logtype . "\n";
}
if (Settings::Get('system.logfiles_type') == '2' && Settings::Get('system.logfiles_format') == '') {
$logtype = 'vhost_combined';
@@ -986,9 +991,11 @@ class Apache extends HttpConfigBase
$vhost_content .= ' SSLOpenSSLConfCmd DHParameters "' . $dhparams . '"' . "\n";
}
$vhost_content .= ' SSLCompression Off' . "\n";
if (Settings::Get('system.sessionticketsenabled') == '1') {
$vhost_content .= ' SSLSessionTickets ' . ($domain['ssl_sessiontickets'] == '1' ? 'on' : 'off') . "\n";
}
// this makes it more secure, thx to Marcel (08/2013)
$vhost_content .= ' SSLHonorCipherOrder On' . "\n";
}
$vhost_content .= ' SSLHonorCipherOrder ' . ($domain['ssl_honorcipherorder'] == '1' ? 'on' : 'off') . "\n";
$vhost_content .= ' SSLCipherSuite ' . $ssl_cipher_list . "\n";
$protocols = array_map('trim', explode(",", $ssl_protocols));
if (in_array("TLSv1.3", $protocols) && ! empty($tlsv13_cipher_list) && Settings::Get('system.apache24') == 1) {
@@ -1114,7 +1121,7 @@ class Apache extends HttpConfigBase
// Create vhost without ssl
$this->virtualhosts_data[$vhosts_filename] .= $this->getVhostContent($domain, false);
if ($domain['ssl'] == '1' || $domain['ssl_redirect'] == '1') {
if ($domain['ssl_enabled'] == '1' && ($domain['ssl'] == '1' || $domain['ssl_redirect'] == '1')) {
// Adding ssl stuff if enabled
$vhosts_filename_ssl = $this->getVhostFilename($domain, true);
$this->virtualhosts_data[$vhosts_filename_ssl] = '# Domain ID: ' . $domain['id'] . ' (SSL) - CustomerID: ' . $domain['customerid'] . ' - CustomerLogin: ' . $domain['loginname'] . "\n";

View File

@@ -68,6 +68,11 @@ class DomainSSL
'ssl_key_file' => \Froxlor\FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '.key')
);
if (! $this->validateCertificate($dom_certs)) {
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_ERR, 'Given SSL private key for ' . $domain['domain'] . ' does not seem to match the certificate. Cannot create ssl-directives');
return;
}
if (Settings::Get('system.webserver') == 'lighttpd') {
// put my.crt and my.key together for lighty.
$dom_certs['ssl_cert_file'] = trim($dom_certs['ssl_cert_file']) . "\n" . trim($dom_certs['ssl_key_file']) . "\n";
@@ -112,4 +117,9 @@ class DomainSSL
return;
}
private function validateCertificate($dom_certs = array())
{
return openssl_x509_check_private_key($dom_certs['ssl_cert_file'], $dom_certs['ssl_key_file']);
}
}

View File

@@ -4,6 +4,9 @@ namespace Froxlor\Cron\Http\LetsEncrypt;
use Froxlor\FroxlorLogger;
use Froxlor\Settings;
use Froxlor\Database\Database;
use Froxlor\PhpHelper;
use Froxlor\Domain\Domain;
use Froxlor\FileDir;
/**
* This file is part of the Froxlor project.
@@ -41,11 +44,405 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron
*/
private static $upddom_stmt = null;
private static $do_update = true;
public static $no_inserttask = false;
private static function needRenew()
/**
* run the task
*
* @param boolean $internal
* @return number
*/
public static function run($internal = false)
{
// usually, this is action is called from within the tasks-jobs
if (! defined('CRON_IS_FORCED') && ! defined('CRON_DEBUG_FLAG') && $internal == false) {
// Let's Encrypt cronjob is combined with regeneration of webserver configuration files.
// For debugging purposes you can use the --debug switch and the --force switch to run the cron manually.
// check whether we MIGHT need to run although there is no task to regenerate config-files
$needRenew = self::issueDomains();
if ($needRenew || self::issueFroxlorVhost()) {
// insert task to generate certificates and vhost-configs
\Froxlor\System\Cronjob::inserttask(1);
}
return 0;
}
// set server according to settings
self::$apiserver = 'https://acme-' . (Settings::Get('system.letsencryptca') == 'testing' ? 'staging-' : '') . 'v0' . \Froxlor\Settings::Get('system.leapiversion') . '.api.letsencrypt.org/directory';
// validate acme.sh installation
if (! self::checkInstall()) {
return - 1;
}
self::checkUpgrade();
// flag for re-generation of vhost files
$changedetected = 0;
// prepare update sql
self::$updcert_stmt = Database::prepare("
REPLACE INTO
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
SET
`id` = :id,
`domainid` = :domainid,
`ssl_cert_file` = :crt,
`ssl_key_file` = :key,
`ssl_ca_file` = :ca,
`ssl_cert_chainfile` = :chain,
`ssl_csr_file` = :csr,
`ssl_fullchain_file` = :fullchain,
`expirationdate` = :expirationdate
");
// prepare domain update sql
self::$upddom_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `ssl_redirect` = '1' WHERE `id` = :domainid");
// check whether there are certificates to issue
$issue_froxlor = self::issueFroxlorVhost();
$issue_domains = self::issueDomains();
// first - generate LE for system-vhost if enabled
if ($issue_froxlor) {
// build row
$certrow = array(
'loginname' => 'froxlor.panel',
'domain' => Settings::Get('system.hostname'),
'domainid' => 0,
'documentroot' => \Froxlor\Froxlor::getInstallDir(),
'leprivatekey' => Settings::Get('system.leprivatekey'),
'lepublickey' => Settings::Get('system.lepublickey'),
'leregistered' => Settings::Get('system.leregistered'),
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
'expirationdate' => null,
'ssl_cert_file' => null,
'ssl_key_file' => null,
'ssl_ca_file' => null,
'ssl_csr_file' => null,
'id' => null
);
// add to queue
$issue_domains[] = $certrow;
}
if (count($issue_domains)) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Requesting " . count($issue_domains) . " new Let's Encrypt certificates");
self::runIssueFor($issue_domains);
$changedetected = 1;
}
// compare file-system certificates with the ones in our database
// and update if needed
$renew_froxlor = self::renewFroxlorVhost();
$renew_domains = self::renewDomains();
if ($renew_froxlor) {
// build row
$certrow = array(
'loginname' => 'froxlor.panel',
'domain' => Settings::Get('system.hostname'),
'domainid' => 0,
'documentroot' => \Froxlor\Froxlor::getInstallDir(),
'leprivatekey' => Settings::Get('system.leprivatekey'),
'lepublickey' => Settings::Get('system.lepublickey'),
'leregistered' => Settings::Get('system.leregistered'),
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
'expirationdate' => is_array($renew_froxlor) ? $renew_froxlor['expirationdate'] : date('Y-m-d H:i:s', 0),
'ssl_cert_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_cert_file'] : null,
'ssl_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_csr_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_csr_file'] : null,
'id' => is_array($renew_froxlor) ? $renew_froxlor['id'] : null
);
$renew_domains[] = $certrow;
}
foreach ($renew_domains as $domain) {
$cronlog = FroxlorLogger::getInstanceOf(array(
'loginname' => $domain['loginname'],
'adminsession' => 0
));
if (defined('CRON_IS_FORCED') || self::checkFsFilesAreNewer($domain['domain'], $domain['expirationdate'])) {
self::certToDb($domain, $cronlog, array());
$changedetected = 1;
}
}
// If we have a change in a certificate, we need to update the webserver - configs
// This is easiest done by just creating a new task ;)
if ($changedetected) {
if (self::$no_inserttask == false) {
\Froxlor\System\Cronjob::inserttask(1);
}
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Let's Encrypt certificates have been updated");
} else {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "No new certificates or certificate updates found");
}
}
/**
* issue certificates for a list of domains
*/
private static function runIssueFor($certrows = array())
{
// prepare aliasdomain-check
$aliasdomains_stmt = Database::prepare("
SELECT
dom.`id` as domainid,
dom.`domain`,
dom.`wwwserveralias`
FROM `" . TABLE_PANEL_DOMAINS . "` AS dom
WHERE
dom.`aliasdomain` = :id
AND dom.`letsencrypt` = 1
AND dom.`iswildcarddomain` = 0
");
// iterate through all domains
foreach ($certrows as $certrow) {
// set logger to corresponding loginname for the log to appear in the users system-log
$cronlog = FroxlorLogger::getInstanceOf(array(
'loginname' => $certrow['loginname'],
'adminsession' => 0
));
// Only issue let's encrypt certificate if no broken ssl_redirect is enabled
if ($certrow['ssl_redirect'] != 2) {
$do_force = false;
if (! empty($certrow['ssl_cert_file']) && empty($certrow['expirationdate'])) {
// domain changed (SAN or similar)
$do_force = true;
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']);
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Creating certificate for " . $certrow['domain']);
}
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding common-name: " . $certrow['domain']);
$domains = array(
strtolower($certrow['domain'])
);
// add www.<domain> to SAN list
if ($certrow['wwwserveralias'] == 1) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $certrow['domain']);
$domains[] = strtolower('www.' . $certrow['domain']);
}
if ($certrow['domainid'] == 0) {
$froxlor_aliases = Settings::Get('system.froxloraliases');
if (! empty($froxlor_aliases)) {
$froxlor_aliases = explode(",", $froxlor_aliases);
foreach ($froxlor_aliases as $falias) {
if (\Froxlor\Validate\Validate::validateDomain(trim($falias))) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . strtolower(trim($falias)));
$domains[] = strtolower(trim($falias));
}
}
}
} else {
// add alias domains (and possibly www.<aliasdomain>) to SAN list
Database::pexecute($aliasdomains_stmt, array(
'id' => $certrow['domainid']
));
$aliasdomains = $aliasdomains_stmt->fetchAll(\PDO::FETCH_ASSOC);
foreach ($aliasdomains as $aliasdomain) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . $aliasdomain['domain']);
$domains[] = strtolower($aliasdomain['domain']);
if ($aliasdomain['wwwserveralias'] == 1) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $aliasdomain['domain']);
$domains[] = strtolower('www.' . $aliasdomain['domain']);
}
}
}
self::validateDns($domains, $certrow['domainid'], $cronlog);
self::runAcmeSh($certrow, $domains, $cronlog, $do_force);
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $certrow['domain'] . " due to an enabled ssl_redirect");
}
}
}
/**
* validate dns (A / AAAA record) of domain against known system ips
*
* @param array $domains
* @param int $domain_id
* @param FroxlorLogger $cronlog
*/
private static function validateDns(&$domains = array(), $domain_id, &$cronlog)
{
if (Settings::Get('system.le_domain_dnscheck') == '1' && ! empty($domains)) {
$loop_domains = $domains;
// ips according to our system
$our_ips = Domain::getIpsOfDomain($domain_id);
foreach ($loop_domains as $idx => $domain) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Validating DNS of " . $domain);
// ips accordint to NS
$domain_ips = PhpHelper::gethostbynamel6($domain);
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
// 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");
unset($domains[$idx]);
}
}
}
}
private static function runAcmeSh($certrow = array(), $domains = array(), &$cronlog = null, $force = false)
{
if (! empty($domains)) {
$acmesh_cmd = self::$acmesh . " --server " . self::$apiserver . " --issue -d " . implode(" -d ", $domains);
// challenge path
$acmesh_cmd .= " -w " . Settings::Get('system.letsencryptchallengepath');
if (Settings::Get('system.leecc') > 0) {
// ecc certificate
$acmesh_cmd .= " --keylength ec-" . Settings::Get('system.leecc');
} else {
$acmesh_cmd .= " --keylength " . Settings::Get('system.letsencryptkeysize');
}
if (Settings::Get('system.letsencryptreuseold') != '1') {
$acmesh_cmd .= " --always-force-new-domain-key";
}
if (Settings::Get('system.letsencryptca') == 'testing') {
$acmesh_cmd .= " --staging";
}
if ($force) {
$acmesh_cmd .= " --force";
}
if (defined('CRON_DEBUG_FLAG')) {
$acmesh_cmd .= " --debug";
}
$acme_result = \Froxlor\FileDir::safe_exec($acmesh_cmd);
// debug output of acme.sh run
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, implode("\n", $acme_result));
self::certToDb($certrow, $cronlog, $acme_result);
}
}
private static function certToDb($certrow, &$cronlog, $acme_result)
{
$return = array();
self::readCertificateToVar(strtolower($certrow['domain']), $return, $cronlog);
if (! empty($return['crt'])) {
$newcert = openssl_x509_parse($return['crt']);
if ($newcert) {
// Store the new data
Database::pexecute(self::$updcert_stmt, array(
'id' => $certrow['id'],
'domainid' => $certrow['domainid'],
'crt' => $return['crt'],
'key' => $return['key'],
'ca' => $return['chain'],
'chain' => $return['chain'],
'csr' => $return['csr'],
'fullchain' => $return['fullchain'],
'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t'])
));
if ($certrow['ssl_redirect'] == 3) {
Database::pexecute(self::$upddom_stmt, array(
'domainid' => $certrow['domainid']
));
}
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Updated Let's Encrypt certificate for " . $certrow['domain']);
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Got non-successful Let's Encrypt response for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result));
}
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not get Let's Encrypt certificate for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result));
}
}
/**
* check whether we need to issue a new certificate for froxlor itself
*
* @return boolean
*/
private static function issueFroxlorVhost()
{
if (Settings::Get('system.le_froxlor_enabled') == '1') {
// let's encrypt is enabled, now check whether we have a certificate
$froxlor_ssl_settings_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
WHERE `domainid` = '0'
");
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
// also check for possible existing certificate
if (! $froxlor_ssl && ! self::checkFsFilesAreNewer(Settings::Get('system.hostname'), date('Y-m-d H:i:s'))) {
return true;
}
}
return false;
}
/**
* check whether we need to renew-check the certificate for froxlor itself
*
* @return boolean
*/
private static function renewFroxlorVhost()
{
if (Settings::Get('system.le_froxlor_enabled') == '1') {
// let's encrypt is enabled, now check whether we have a certificate
$froxlor_ssl_settings_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
WHERE `domainid` = '0'
");
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
// also check for possible existing certificate
if ($froxlor_ssl || (! $froxlor_ssl && ! self::checkFsFilesAreNewer(Settings::Get('system.hostname'), date('Y-m-d H:i:s', 0)))) {
return ($froxlor_ssl ? $froxlor_ssl : true);
}
}
return false;
}
/**
* get a list of domains that have a lets encrypt certificate (possible renew)
*/
private static function renewDomains()
{
$certificates_stmt = Database::query("
SELECT
domssl.`id`,
domssl.`domainid`,
domssl.`expirationdate`,
domssl.`ssl_cert_file`,
domssl.`ssl_key_file`,
dom.`domain`,
dom.`id` AS 'domainid',
dom.`ssl_redirect`,
cust.`loginname`
FROM
`" . TABLE_PANEL_CUSTOMERS . "` AS cust,
`" . TABLE_PANEL_DOMAINS . "` AS dom
LEFT JOIN
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` AS domssl ON
dom.`id` = domssl.`domainid`
WHERE
dom.`customerid` = cust.`customerid`
AND cust.deactivated = 0
AND dom.`letsencrypt` = 1
AND dom.`aliasdomain` IS NULL
AND dom.`iswildcarddomain` = 0
");
$renew_certs = $certificates_stmt->fetchAll(\PDO::FETCH_ASSOC);
if ($renew_certs) {
return $renew_certs;
}
return array();
}
/**
* get a list of domains that require a new certificate (issue)
*/
private static function issueDomains()
{
$certificates_stmt = Database::query("
SELECT
@@ -78,311 +475,70 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron
AND dom.`letsencrypt` = 1
AND dom.`aliasdomain` IS NULL
AND dom.`iswildcarddomain` = 0
AND (
domssl.`expirationdate` < DATE_ADD(NOW(), INTERVAL 30 DAY)
OR domssl.`expirationdate` IS NULL
)
AND domssl.`expirationdate` IS NULL
");
$customer_ssl = $certificates_stmt->fetchAll(\PDO::FETCH_ASSOC);
$froxlor_ssl = array();
if (Settings::Get('system.le_froxlor_enabled') == '1') {
$froxlor_ssl_settings_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
WHERE `domainid` = '0' AND
(`expirationdate` < DATE_ADD(NOW(), INTERVAL 30 DAY) OR `expirationdate` IS NULL)
");
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
if ($customer_ssl) {
return $customer_ssl;
}
return array();
}
if (count($customer_ssl) > 0 || count($froxlor_ssl) > 0) {
return array(
'customer_ssl' => $customer_ssl,
'froxlor_ssl' => $froxlor_ssl
);
private static function checkFsFilesAreNewer($domain, $cert_date = 0)
{
$certificate_folder = self::getWorkingDirFromEnv($domain);
$ssl_file = \Froxlor\FileDir::makeCorrectFile($certificate_folder . '/' . $domain . '.cer');
if (is_dir($certificate_folder) && file_exists($ssl_file) && is_readable($ssl_file)) {
$cert_data = openssl_x509_parse(file_get_contents($ssl_file));
if ($cert_data['validTo_time_t'] > strtotime($cert_date)) {
return true;
}
}
return false;
}
public static function run($internal = false)
public static function getWorkingDirFromEnv($domain = "", $forced_noecc = false)
{
if (! defined('CRON_IS_FORCED') && ! defined('CRON_DEBUG_FLAG') && $internal == false) {
// Let's Encrypt cronjob is combined with regeneration of webserver configuration files.
// For debugging purposes you can use the --debug switch and the --force switch to run the cron manually.
// check whether we MIGHT need to run although there is no task to regenerate config-files
$needRenew = self::needRenew();
if ($needRenew) {
// insert task to generate certificates and vhost-configs
\Froxlor\System\Cronjob::inserttask(1);
if (Settings::Get('system.leecc') > 0 && ! $forced_noecc) {
$domain .= "_ecc";
}
return 0;
}
self::checkInstall();
self::$apiserver = 'https://acme-v0' . \Froxlor\Settings::Get('system.leapiversion') . '.api.letsencrypt.org/directory';
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Requesting/renewing Let's Encrypt certificates");
$aliasdomains_stmt = Database::prepare("
SELECT
dom.`id` as domainid,
dom.`domain`,
dom.`wwwserveralias`
FROM `" . TABLE_PANEL_DOMAINS . "` AS dom
WHERE
dom.`aliasdomain` = :id
AND dom.`letsencrypt` = 1
AND dom.`iswildcarddomain` = 0
");
self::$updcert_stmt = Database::prepare("
REPLACE INTO
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
SET
`id` = :id,
`domainid` = :domainid,
`ssl_cert_file` = :crt,
`ssl_key_file` = :key,
`ssl_ca_file` = :ca,
`ssl_cert_chainfile` = :chain,
`ssl_csr_file` = :csr,
`ssl_fullchain_file` = :fullchain,
`expirationdate` = :expirationdate
");
self::$upddom_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `ssl_redirect` = '1' WHERE `id` = :domainid");
// flag for re-generation of vhost files
$changedetected = 0;
$needRenew = self::needRenew();
// first - generate LE for system-vhost if enabled
if (Settings::Get('system.le_froxlor_enabled') == '1') {
$certrow = array(
'loginname' => 'froxlor.panel',
'domain' => Settings::Get('system.hostname'),
'domainid' => 0,
'documentroot' => \Froxlor\Froxlor::getInstallDir(),
'leprivatekey' => Settings::Get('system.leprivatekey'),
'lepublickey' => Settings::Get('system.lepublickey'),
'leregistered' => Settings::Get('system.leregistered'),
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
'expirationdate' => null,
'ssl_cert_file' => null,
'ssl_key_file' => null,
'ssl_ca_file' => null,
'ssl_csr_file' => null,
'id' => null
);
$froxlor_ssl = $needRenew['froxlor_ssl'];
$cert_mode = 'issue';
if ($froxlor_ssl) {
$cert_mode = 'renew';
$certrow['id'] = $froxlor_ssl['id'];
$certrow['expirationdate'] = $froxlor_ssl['expirationdate'];
$certrow['ssl_cert_file'] = $froxlor_ssl['ssl_cert_file'];
$certrow['ssl_key_file'] = $froxlor_ssl['ssl_key_file'];
$certrow['ssl_ca_file'] = $froxlor_ssl['ssl_ca_file'];
$certrow['ssl_csr_file'] = $froxlor_ssl['ssl_csr_file'];
} else {
// check whether we have an entry with valid certificates which just does not need
// updating yet, so we need to skip this here
$froxlor_ssl_settings_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = '0'
");
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
if ($froxlor_ssl && ! empty($froxlor_ssl['ssl_cert_file'])) {
$cert_mode = false;
}
}
if ($cert_mode) {
$domains = array(
$certrow['domain']
);
$froxlor_aliases = Settings::Get('system.froxloraliases');
if (! empty($froxlor_aliases)) {
$froxlor_aliases = explode(",", $froxlor_aliases);
foreach ($froxlor_aliases as $falias) {
if (\Froxlor\Validate\Validate::validateDomain(trim($falias))) {
$domains[] = trim($falias);
$env_file = FileDir::makeCorrectFile(dirname(self::$acmesh) . '/acme.sh.env');
if (file_exists($env_file)) {
$output = [];
$cut = <<<EOC
cut -d'"' -f2
EOC;
exec('grep "LE_WORKING_DIR" ' . escapeshellarg($env_file) . ' | ' . $cut, $output);
if (is_array($output) && ! empty($output) && isset($output[0]) && ! empty($output[0])) {
return FileDir::makeCorrectDir($output[0] . "/" . $domain);
}
}
return FileDir::makeCorrectDir(dirname(self::$acmesh) . "/" . $domain);
}
// Only renew let's encrypt certificate if no broken ssl_redirect is enabled
// - this temp. deactivation of the ssl-redirect is handled by the webserver-cronjob
$do_force = false;
if ($cert_mode == 'renew') {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Updating certificate for " . $certrow['domain']);
} else {
$do_force = true;
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Creating certificate for " . $certrow['domain']);
}
$cronlog = FroxlorLogger::getInstanceOf(array(
'loginname' => $certrow['loginname'],
'adminsession' => 0
));
self::runAcmeSh($certrow, $domains, $cert_mode, $cronlog, $changedetected, $do_force);
}
}
// customer domains
$certrows = $needRenew['customer_ssl'];
$cert_mode = 'issue';
foreach ($certrows as $certrow) {
// set logger to corresponding loginname for the log to appear in the users system-log
$cronlog = FroxlorLogger::getInstanceOf(array(
'loginname' => $certrow['loginname'],
'adminsession' => 0
));
// Only renew let's encrypt certificate if no broken ssl_redirect is enabled
if ($certrow['ssl_redirect'] != 2) {
$do_force = false;
if (! empty($certrow['ssl_cert_file']) && ! empty($certrow['expirationdate'])) {
$cert_mode = 'renew';
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Updating certificate for " . $certrow['domain']);
} else if (! empty($certrow['ssl_cert_file']) && empty($certrow['expirationdate'])) {
// domain changed (SAN or similar)
$do_force = true;
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']);
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Creating certificate for " . $certrow['domain']);
}
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . $certrow['domain']);
$domains = array(
$certrow['domain']
);
// add www.<domain> to SAN list
if ($certrow['wwwserveralias'] == 1) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $certrow['domain']);
$domains[] = 'www.' . $certrow['domain'];
}
// add alias domains (and possibly www.<aliasdomain>) to SAN list
Database::pexecute($aliasdomains_stmt, array(
'id' => $certrow['domainid']
));
$aliasdomains = $aliasdomains_stmt->fetchAll(\PDO::FETCH_ASSOC);
foreach ($aliasdomains as $aliasdomain) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . $aliasdomain['domain']);
$domains[] = $aliasdomain['domain'];
if ($aliasdomain['wwwserveralias'] == 1) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $aliasdomain['domain']);
$domains[] = 'www.' . $aliasdomain['domain'];
}
}
self::runAcmeSh($certrow, $domains, $cert_mode, $cronlog, $changedetected, $do_force);
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $certrow['domain'] . " due to an enabled ssl_redirect");
}
}
// If we have a change in a certificate, we need to update the webserver - configs
// This is easiest done by just creating a new task ;)
if ($changedetected) {
if (self::$no_inserttask == false) {
\Froxlor\System\Cronjob::inserttask(1);
}
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Let's Encrypt certificates have been updated");
} else {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "No new certificates or certificates due for renewal found");
}
}
private static function runAcmeSh($certrow = array(), $domains = array(), $cert_mode = 'issue', &$cronlog = null, &$changedetected = 0, $force = false)
public static function getAcmeSh()
{
if (! empty($domains)) {
if (self::$do_update) {
self::checkUpgrade();
self::$do_update = false;
return self::$acmesh;
}
$acmesh_cmd = self::$acmesh . " --auto-upgrade 0 --server " . self::$apiserver . " --" . $cert_mode . " -d " . implode(" -d ", $domains);
if ($cert_mode == 'issue') {
$acmesh_cmd .= " -w " . Settings::Get('system.letsencryptchallengepath');
}
/**
* get certificate files from filesystem and store in $return array
*
* @param string $domain
* @param array $return
* @param object $cronlog
*/
private static function readCertificateToVar($domain, &$return, &$cronlog)
{
$certificate_folder = self::getWorkingDirFromEnv($domain);
$certificate_folder_noecc = null;
if (Settings::Get('system.leecc') > 0) {
$acmesh_cmd .= " --keylength ec-" . Settings::Get('system.leecc');
} else {
$acmesh_cmd .= " --keylength " . Settings::Get('system.letsencryptkeysize');
}
if (Settings::Get('system.letsencryptreuseold') != '1') {
$acmesh_cmd .= " --always-force-new-domain-key";
}
if (Settings::Get('system.letsencryptca') == 'testing') {
$acmesh_cmd .= " --staging";
}
if ($force) {
$acmesh_cmd .= " --force";
}
$acme_result = \Froxlor\FileDir::safe_exec($acmesh_cmd);
// debug output of acme.sh run
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, implode("\n", $acme_result));
$return = array();
self::readCertificateToVar($certrow['domain'], $return);
if (! empty($return['crt'])) {
$newcert = openssl_x509_parse($return['crt']);
if ($newcert) {
// Store the new data
Database::pexecute(self::$updcert_stmt, array(
'id' => $certrow['id'],
'domainid' => $certrow['domainid'],
'crt' => $return['crt'],
'key' => $return['key'],
'ca' => $return['chain'],
'chain' => $return['chain'],
'csr' => $return['csr'],
'fullchain' => $return['fullchain'],
'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t'])
));
if ($certrow['ssl_redirect'] == 3) {
Database::pexecute(self::$upddom_stmt, array(
'domainid' => $certrow['domainid']
));
}
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Updated Let's Encrypt certificate for " . $certrow['domain']);
$changedetected = 1;
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Got non-successful Let's Encrypt response for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result));
}
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not get Let's Encrypt certificate for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result));
}
}
}
private static function readCertificateToVar($domain, &$return)
{
$certificate_folder = dirname(self::$acmesh) . "/" . $domain;
if (Settings::Get('system.leecc') > 0) {
$certificate_folder .= "_ecc";
$certificate_folder_noecc = self::getWorkingDirFromEnv($domain, true);
}
$certificate_folder = \Froxlor\FileDir::makeCorrectDir($certificate_folder);
if (is_dir($certificate_folder)) {
if (is_dir($certificate_folder) || is_dir($certificate_folder_noecc)) {
foreach ([
'crt' => $domain . '.cer',
'key' => $domain . '.key',
@@ -394,28 +550,52 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron
if (file_exists($ssl_file)) {
$return[$index] = file_get_contents($ssl_file);
} else {
if (! empty($certificate_folder_noecc)) {
$ssl_file_fb = \Froxlor\FileDir::makeCorrectFile($certificate_folder_noecc . '/' . $sslfile);
if (file_exists($ssl_file_fb)) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "ECC certificates activated but found only non-ecc file");
$return[$index] = file_get_contents($ssl_file_fb);
continue;
}
}
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find file '" . $sslfile . "' in '" . $certificate_folder . "'");
$return[$index] = null;
}
}
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find certificate-folder '" . $certificate_folder . "'");
}
}
private static function checkInstall()
/**
* install acme.sh if not found yet
*/
private static function checkInstall($tries = 0)
{
if (! file_exists(self::$acmesh)) {
if (! file_exists(self::$acmesh) && $tries > 0) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Download/installation of acme.sh seems to have failed. Re-run cronjob to try again or install manually to '" . self::$acmesh . "'");
echo PHP_EOL . "Download/installation of acme.sh seems to have failed. Re-run cronjob to try again or install manually to '" . self::$acmesh . "'" . PHP_EOL;
return false;
} else if (! file_exists(self::$acmesh)) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Could not find acme.sh - installing it to /root/.acme.sh/");
$return = false;
\Froxlor\FileDir::safe_exec("wget -O - https://get.acme.sh | sh", $return, array(
'|'
));
// check whether the installation worked
return self::checkInstall(++ $tries);
}
return true;
}
/**
* run upgrade
*/
private static function checkUpgrade()
{
$acmesh_result = \Froxlor\FileDir::safe_exec(self::$acmesh . " --upgrade");
// check for activated cron (which is installed automatically) but we don't need it
$acmesh_result2 = \Froxlor\FileDir::safe_exec(self::$acmesh . " --uninstall-cronjob");
$acmesh_result = \Froxlor\FileDir::safe_exec(self::$acmesh . " --upgrade --auto-upgrade 0");
// check for activated cron
$acmesh_result2 = \Froxlor\FileDir::safe_exec(self::$acmesh . " --install-cronjob");
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Checking for LetsEncrypt client upgrades before renewing certificates:\n" . implode("\n", $acmesh_result) . "\n" . implode("\n", $acmesh_result2));
}
}

View File

@@ -432,7 +432,7 @@ class Lighttpd extends HttpConfigBase
protected function getVhostContent($domain, $ssl_vhost = false, $ipid = 0)
{
if ($ssl_vhost === true && $domain['ssl'] != '1' && $domain['ssl_redirect'] != '1') {
if ($ssl_vhost === true && $domain['ssl'] != '1' && $domain['ssl_enabled'] != '1' && $domain['ssl_redirect'] != '1') {
return '';
}
@@ -586,7 +586,7 @@ class Lighttpd extends HttpConfigBase
$ssl_settings .= 'ssl.use-sslv2 = "disable"' . "\n";
$ssl_settings .= 'ssl.use-sslv3 = "disable"' . "\n";
$ssl_settings .= 'ssl.cipher-list = "' . $ssl_cipher_list . '"' . "\n";
$ssl_settings .= 'ssl.honor-cipher-order = "enable"' . "\n";
$ssl_settings .= 'ssl.honor-cipher-order = ' . ($domain['ssl_honorcipherorder'] == '1' ? '"enable"' : '"disable"') . "\n";
$ssl_settings .= 'ssl.pemfile = "' . \Froxlor\FileDir::makeCorrectFile($domain['ssl_cert_file']) . '"' . "\n";
if ($domain['ssl_ca_file'] != '') {

View File

@@ -71,7 +71,7 @@ class Nginx extends HttpConfigBase
}
$logtype = 'frx_custom';
$this->nginx_data[$vhosts_filename] = 'log_format ' . $logtype . ' "' . Settings::Get('system.logfiles_format') . '";' . "\n";
$this->nginx_data[$vhosts_filename] = 'log_format ' . $logtype . ' ' . Settings::Get('system.logfiles_format') . ';' . "\n";
}
}
@@ -226,7 +226,12 @@ class Nginx extends HttpConfigBase
$aliases = " " . trim($aliases);
}
$this->nginx_data[$vhost_filename] .= "\t" . 'server_name ' . Settings::Get('system.hostname') . $aliases . ';' . "\n";
$this->nginx_data[$vhost_filename] .= "\t" . 'access_log /var/log/nginx/access.log;' . "\n";
$logtype = 'combined';
if (Settings::Get('system.logfiles_format') != '') {
$logtype = 'frx_custom';
}
$this->nginx_data[$vhost_filename] .= "\t" . 'access_log /var/log/nginx/access.log ' . $logtype . ';' . "\n";
if (Settings::Get('system.use_ssl') == '1' && Settings::Get('system.leenabled') == '1' && Settings::Get('system.le_froxlor_enabled') == '1') {
$acmeConfFilename = Settings::Get('system.letsencryptacmeconf');
@@ -272,6 +277,8 @@ class Nginx extends HttpConfigBase
*/
if ($row_ipsandports['ssl'] == '1') {
$row_ipsandports['domain'] = Settings::Get('system.hostname');
$row_ipsandports['ssl_honorcipherorder'] = Settings::Get('system.honorcipherorder');
$row_ipsandports['ssl_sessiontickets'] = Settings::Get('system.sessiontickets');
$this->nginx_data[$vhost_filename] .= $this->composeSslSettings($row_ipsandports);
if ($row_ipsandports['ssl_specialsettings'] != '') {
$this->nginx_data[$vhost_filename] .= $this->processSpecialConfigTemplate($row_ipsandports['ssl_specialsettings'], array(
@@ -537,7 +544,7 @@ class Nginx extends HttpConfigBase
}
if ($domain['ssl_specialsettings'] != '' && $ssl_vhost == true) {
$vhost_content .= $this->processSpecialConfigTemplate($domain['ssl_specialsettings'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n";
$vhost_content = $this->mergeVhostCustom($vhost_content, $this->processSpecialConfigTemplate($domain['ssl_specialsettings'], $domain, $domain['ip'], $domain['port'], $ssl_vhost));
}
if ($_vhost_content != '') {
@@ -549,7 +556,7 @@ class Nginx extends HttpConfigBase
}
if (Settings::Get('system.default_sslvhostconf') != '' && $ssl_vhost == true) {
$vhost_content .= $this->processSpecialConfigTemplate(Settings::Get('system.default_sslvhostconf'), $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n";
$vhost_content = $this->mergeVhostCustom($vhost_content, $this->processSpecialConfigTemplate(Settings::Get('system.default_sslvhostconf'), $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n");
}
}
}
@@ -562,6 +569,8 @@ class Nginx extends HttpConfigBase
{
// Remove windows linebreaks
$vhost = str_replace("\r", "\n", $vhost);
// remove comments
$vhost = implode("\n", preg_replace('/^(\s+)?#(.*)$/', '', explode("\n", $vhost)));
// Break blocks into lines
$vhost = str_replace(array(
"{",
@@ -691,14 +700,17 @@ class Nginx extends HttpConfigBase
if (! file_exists($dhparams)) {
\Froxlor\FileDir::safe_exec('openssl dhparam -out ' . escapeshellarg($dhparams) . ' 4096');
}
$sslsettings .= 'ssl_dhparam ' . $dhparams . ';' . "\n";
$sslsettings .= "\t" . 'ssl_dhparam ' . $dhparams . ';' . "\n";
}
// When <1.11.0: Defaults to prime256v1, similar to first curve recommendation by Mozilla.
// (When specifyng just one, there's no fallback when specific curve is not supported by client.)
// When >1.11.0: Defaults to auto, using recommended curves provided by OpenSSL.
// see https://github.com/Froxlor/Froxlor/issues/652
// $sslsettings .= "\t" . 'ssl_ecdh_curve secp384r1;' . "\n";
$sslsettings .= "\t" . 'ssl_prefer_server_ciphers on;' . "\n";
$sslsettings .= "\t" . 'ssl_prefer_server_ciphers ' . (isset($domain_or_ip['ssl_honorcipherorder']) && $domain_or_ip['ssl_honorcipherorder'] == '1' ? 'on' : 'off') . ';' . "\n";
if (Settings::Get('system.sessionticketsenabled') == '1') {
$sslsettings .= "\t" . 'ssl_session_tickets ' . (isset($domain_or_ip['ssl_sessiontickets']) && $domain_or_ip['ssl_sessiontickets'] == '1' ? 'on' : 'off') . ';' . "\n";
}
$sslsettings .= "\t" . 'ssl_session_cache shared:SSL:10m;' . "\n";
$sslsettings .= "\t" . 'ssl_certificate ' . \Froxlor\FileDir::makeCorrectFile($domain_or_ip['ssl_cert_file']) . ';' . "\n";

View File

@@ -115,6 +115,7 @@ class Fpm
$fpm_requests = (int) $this->fpm_cfg['max_requests'];
$fpm_process_idle_timeout = (int) $this->fpm_cfg['idle_timeout'];
$fpm_limit_extensions = $this->fpm_cfg['limit_extensions'];
$fpm_custom_config = $this->fpm_cfg['custom_config'];
if ($fpm_children == 0) {
$fpm_children = 1;
@@ -260,6 +261,12 @@ class Fpm
$fpm_config .= 'php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f ' . $this->domain['email'] . "\n";
}
// append custom phpfpm configuration
if (! empty($fpm_custom_config)) {
$fpm_config .= "\n; Custom Configuration\n";
$fpm_config .= \Froxlor\PhpHelper::replaceVariables($fpm_custom_config, $php_ini_variables);
}
fwrite($fh, $fpm_config, strlen($fpm_config));
fclose($fh);
}

View File

@@ -77,6 +77,7 @@ class BackupCron extends \Froxlor\Cron\FroxlorCron
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :id");
$cronlog = FroxlorLogger::getInstanceOf();
$all_jobs = $result_tasks_stmt->fetchAll();
foreach ($all_jobs as $row) {
@@ -96,7 +97,7 @@ class BackupCron extends \Froxlor\Cron\FroxlorCron
\Froxlor\FileDir::safe_exec('mkdir -p ' . escapeshellarg($row['data']['destdir']));
}
self::createCustomerBackup($row['data'], $customerdocroot, FroxlorLogger::getInstanceOf());
self::createCustomerBackup($row['data'], $customerdocroot, $cronlog);
}
}

View File

@@ -67,7 +67,7 @@ class Extrausers
'name' => \Froxlor\Customer\Customer::getCustomerDetail($u['customerid'], 'name'),
'company' => \Froxlor\Customer\Customer::getCustomerDetail($u['customerid'], 'company')
);
$u['comment'] = \Froxlor\User::getCorrectUserSalutation($salutation_array);
$u['comment'] = self::cleanString(\Froxlor\User::getCorrectUserSalutation($salutation_array));
if ($u['login_enabled'] != 'Y') {
$u['password'] = '*';
$u['shell'] = '/bin/false';
@@ -90,4 +90,10 @@ class Extrausers
$cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Error when writing ' . $type . ' file entries');
}
}
private static function cleanString($string = null)
{
$allowed = "/[^a-z0-9\\.\\-\\_\\ ]/i";
return preg_replace($allowed, "", $string);
}
}

View File

@@ -418,17 +418,18 @@ class TasksCron extends \Froxlor\Cron\FroxlorCron
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
// We do not want to set a quota for root by accident
if ($row['guid'] != 0) {
$used_quota = isset($usedquota[$row['guid']]) ? $usedquota[$row['guid']]['block']['hard'] : 0;
// The user has no quota in Froxlor, but on the filesystem
if (($row['diskspace'] == 0 || $row['diskspace'] == - 1024) && $usedquota[$row['guid']]['block']['hard'] != 0) {
if (($row['diskspace'] == 0 || $row['diskspace'] == - 1024) && $used_quota != 0) {
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_NOTICE, "Disabling quota for " . $row['loginname']);
if (\Froxlor\FileDir::isFreeBSD()) {
\Froxlor\FileDir::safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -e " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')) . ":0:0 " . $row['guid']);
} else {
\Froxlor\FileDir::safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -u " . $row['guid'] . " -bl 0 -q 0 " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')));
}
} elseif ($row['diskspace'] != $usedquota[$row['guid']]['block']['hard'] && $row['diskspace'] != - 1024) {
} elseif ($row['diskspace'] != $used_quota && $row['diskspace'] != - 1024) {
// The user quota in Froxlor is different than on the filesystem
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_NOTICE, "Setting quota for " . $row['loginname'] . " from " . $usedquota[$row['guid']]['block']['hard'] . " to " . $row['diskspace']);
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_NOTICE, "Setting quota for " . $row['loginname'] . " from " . $used_quota . " to " . $row['diskspace']);
if (\Froxlor\FileDir::isFreeBSD()) {
\Froxlor\FileDir::safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -e " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')) . ":" . $row['diskspace'] . ":" . $row['diskspace'] . " " . $row['guid']);
} else {

View File

@@ -36,7 +36,7 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
if ((int) Settings::Get('system.report_trafficmax') > 0) {
// Warn the customers at xx% traffic-usage
$result_stmt = Database::prepare("
SELECT `c`.`customerid`, `c`.`adminid`, `c`.`name`, `c`.`firstname`,
SELECT `c`.`customerid`, `c`.`customernumber`, `c`.`adminid`, `c`.`name`, `c`.`firstname`,
`c`.`company`, `c`.`traffic`, `c`.`email`, `c`.`def_language`,
`a`.`name` AS `adminname`, `a`.`email` AS `adminmail`,
(SELECT SUM(`t`.`http` + `t`.`ftp_up` + `t`.`ftp_down` + `t`.`mail`)
@@ -55,16 +55,19 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
Database::pexecute($result_stmt, $result_data);
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
if (isset($row['traffic']) && $row['traffic'] > 0 && $row['traffic_used'] != null && (($row['traffic_used'] * 100) / $row['traffic']) >= (int) Settings::Get('system.report_trafficmax')) {
$rep_userinfo = array(
'name' => $row['name'],
'firstname' => $row['firstname'],
'company' => $row['company']
'company' => $row['company'],
'customernumber' => $row['customernumber']
);
$replace_arr = array(
'SALUTATION' => \Froxlor\User::getCorrectUserSalutation($rep_userinfo),
'NAME' => $row['name'], // < keep this for compatibility
'NAME' => $rep_userinfo['name'],
'FIRSTNAME' => $rep_userinfo['firstname'],
'COMPANY' => $rep_userinfo['company'],
'CUSTOMER_NO' => $rep_userinfo['customernumber'],
'TRAFFIC' => round(($row['traffic'] / 1024), 2), /* traffic is stored in KB, template uses MB */
'TRAFFICUSED' => round(($row['traffic_used'] / 1024), 2), /* traffic is stored in KB, template uses MB */
'USAGE_PERCENT' => round(($row['traffic_used'] * 100) / $row['traffic'], 2),
@@ -89,9 +92,11 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
}
// include english language file (fallback)
include_once \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
include \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
// include admin/customer language file
include_once \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
if ($lngfile != 'lng/english.lng.php') {
include \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
}
// Get mail templates from database; the ones from 'admin' are fetched for fallback
$result2_stmt = Database::prepare("
@@ -142,6 +147,8 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
Database::pexecute($upd_stmt, array(
'customerid' => $row['customerid']
));
unset($lng);
}
}
@@ -191,9 +198,11 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
}
// include english language file (fallback)
include_once \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
include \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
// include admin/customer language file
include_once \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
if ($lngfile != 'lng/english.lng.php') {
include \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
}
// Get mail templates from database; the ones from 'admin' are fetched for fallback
$result2_stmt = Database::prepare("
@@ -322,6 +331,8 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
}
$mail->ClearAddresses();
unset($lng);
}
}
} // trafficmax > 0
@@ -343,7 +354,7 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
* report about diskusage for customers
*/
$result_stmt = Database::query("
SELECT `c`.`customerid`, `c`.`adminid`, `c`.`name`, `c`.`firstname`,
SELECT `c`.`customerid`, `c`.`customernumber`, `c`.`adminid`, `c`.`name`, `c`.`firstname`,
`c`.`company`, `c`.`diskspace`, `c`.`diskspace_used`, `c`.`email`, `c`.`def_language`,
`a`.`name` AS `adminname`, `a`.`email` AS `adminmail`
FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c`
@@ -361,11 +372,15 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
$rep_userinfo = array(
'name' => $row['name'],
'firstname' => $row['firstname'],
'company' => $row['company']
'company' => $row['company'],
'customernumber' => $row['customernumber']
);
$replace_arr = array(
'SALUTATION' => \Froxlor\User::getCorrectUserSalutation($rep_userinfo),
'NAME' => $row['name'], // < keep this for compatibility
'NAME' => $rep_userinfo['name'],
'FIRSTNAME' => $rep_userinfo['firstname'],
'COMPANY' => $rep_userinfo['company'],
'CUSTOMER_NO' => $rep_userinfo['customernumber'],
'DISKAVAILABLE' => round(($row['diskspace'] / 1024), 2), /* traffic is stored in KB, template uses MB */
'DISKUSED' => round($row['diskspace_used'] / 1024, 2), /* traffic is stored in KB, template uses MB */
'USAGE_PERCENT' => round(($row['diskspace_used'] * 100) / $row['diskspace'], 2),
@@ -386,13 +401,15 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
$lngfile = Database::pexecute_first($lngfile_stmt, array(
'deflang' => Settings::Get('panel.standardlanguage')
));
$langfile = $lngfile['file'];
$langfile = $lngfile['file'] ?? 'lng/english.lng.php';
}
// include english language file (fallback)
include_once \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
include \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
// include admin/customer language file
include_once \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
if ($lngfile != 'lng/english.lng.php') {
include \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
}
// Get mail templates from database; the ones from 'admin' are fetched for fallback
$result2_stmt = Database::prepare("
@@ -443,6 +460,8 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
Database::pexecute($upd_stmt, array(
'customerid' => $row['customerid']
));
unset($lng);
}
}
@@ -483,9 +502,11 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
}
// include english language file (fallback)
include_once \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
include \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
// include admin/customer language file
include_once \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
if ($lngfile != 'lng/english.lng.php') {
include \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
}
// Get mail templates from database; the ones from 'admin' are fetched for fallback
$result2_stmt = Database::prepare("
@@ -536,6 +557,8 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
Database::pexecute($upd_stmt, array(
'adminid' => $row['adminid']
));
unset($lng);
}
}
} // webmax > 0

View File

@@ -137,7 +137,11 @@ class TrafficCron extends \Froxlor\Cron\FroxlorCron
$mysqlusage_all[$row_database['customerid']] = 0;
}
// sum up result
if ($mysql_usage_row) {
$mysqlusage_all[$row_database['customerid']] += floatval($mysql_usage_row['customerusage']);
} else {
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_WARNING, "Cannot get usage for database " . $row_database['databasename'] . ".");
}
} else {
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_WARNING, "Seems like the database " . $row_database['databasename'] . " had been removed manually.");
}

View File

@@ -30,7 +30,7 @@ class Customer
*
* @return string customers loginname
*/
public function getLoginNameByUid($uid = null)
public static function getLoginNameByUid($uid = null)
{
$result_stmt = Database::prepare("
SELECT `loginname` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `guid` = :guid

View File

@@ -78,12 +78,22 @@ class DbManagerMySQL
public function grantPrivilegesTo($username = null, $password = null, $access_host = null, $p_encrypted = false, $update = false)
{
if (! $update) {
// mysql8 compatibility
if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '8.0.11', '>=')) {
// create user
if ($p_encrypted) {
if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.7.0', '<')) {
$stmt = Database::prepare("
CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED BY PASSWORD :password
");
} else {
$stmt = Database::prepare("
CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED WITH mysql_native_password AS :password
");
}
} else {
$stmt = Database::prepare("
CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED BY :password
");
}
Database::pexecute($stmt, array(
"password" => $password
));
@@ -96,27 +106,20 @@ class DbManagerMySQL
"host" => $access_host
));
} else {
// grant privileges
$stmt = Database::prepare("
GRANT ALL PRIVILEGES ON `" . $username . "`.* TO :username@:host IDENTIFIED BY :password
");
Database::pexecute($stmt, array(
"username" => $username,
"host" => $access_host,
"password" => $password
));
}
} else {
// set passoword
// set password
if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.7.6', '<')) {
if ($p_encrypted) {
$stmt = Database::prepare("SET PASSWORD FOR :username@:host = :password");
} else {
$stmt = Database::prepare("SET PASSWORD FOR :username@:host = PASSWORD(:password)");
}
} else {
if ($p_encrypted) {
$stmt = Database::prepare("ALTER USER :username@:host IDENTIFIED WITH mysql_native_password AS :password");
} else {
$stmt = Database::prepare("ALTER USER :username@:host IDENTIFIED BY :password");
}
}
Database::pexecute($stmt, array(
"username" => $username,
"host" => $access_host,
@@ -158,7 +161,6 @@ class DbManagerMySQL
), false);
}
$drop_stmt = Database::prepare("DROP DATABASE IF EXISTS `" . $dbname . "`");
Database::pexecute($drop_stmt);
}
@@ -247,7 +249,7 @@ class DbManagerMySQL
if ($user_only == false) {
if (! isset($allsqlusers[$row['User']]) || ! is_array($allsqlusers[$row['User']])) {
$allsqlusers[$row['User']] = array(
'password' => $row['Password'],
'password' => $row['Password'] ?? $row['authentication_string'],
'hosts' => array()
);
}

View File

@@ -160,7 +160,7 @@ class Dns
// unset special CAA required-entry
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') {
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($required_entries[$entry['type']][md5("@SPF@")]);
}
@@ -168,6 +168,13 @@ class Dns
// use the first NS entry as primary ns
$primary_ns = $entry['content'];
}
// check for CNAME on @, www- or wildcard-Alias and remove A/AAAA record accordingly
foreach (['@', 'www', '*'] as $crceord) {
if ($entry['type'] == 'CNAME' && $entry['record'] == '@' && (array_key_exists(md5($crceord), $required_entries['A']) || array_key_exists(md5($crceord), $required_entries['AAAA']))) {
unset($required_entries['A'][md5($crceord)]);
unset($required_entries['AAAA'][md5($crceord)]);
}
}
$zonerecords[] = new DnsEntry($entry['record'], $entry['type'], $entry['content'], $entry['prio'], $entry['ttl']);
}

View File

@@ -6,6 +6,41 @@ use Froxlor\Database\Database;
class Domain
{
/**
* return all ip addresses associated with given domain,
* returns all ips if domain-id = 0 (froxlor.vhost)
*
* @param int $domain_id
* @return array
*/
public static function getIpsOfDomain($domain_id)
{
if ($domain_id > 0) {
$sel_stmt = Database::prepare("
SELECT i.ip FROM `" . TABLE_PANEL_IPSANDPORTS . "` `i`
LEFT JOIN `" . TABLE_DOMAINTOIP . "` `dip` ON dip.id_ipandports = i.id
AND dip.id_domain = :domainid
GROUP BY i.ip
");
$sel_param = array(
'domainid' => $domain_id
);
} else {
// assuming froxlor.vhost (id = 0)
$sel_stmt = Database::prepare("
SELECT ip FROM `" . TABLE_PANEL_IPSANDPORTS . "`
GROUP BY ip
");
$sel_param = array();
}
Database::pexecute($sel_stmt, $sel_param);
$result = array();
while ($ip = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $ip['ip'];
}
return $result;
}
/**
* return an array of all enabled redirect-codes
*
@@ -294,13 +329,9 @@ class Domain
public static function doLetsEncryptCleanUp($domainname = null)
{
// @ see \Froxlor\Cron\Http\LetsEncrypt\AcmeSh.php
$acmesh = "/root/.acme.sh/acme.sh";
$acmesh = \Froxlor\Cron\Http\LetsEncrypt\AcmeSh::getAcmeSh();
if (file_exists($acmesh)) {
$certificate_folder = dirname($acmesh) . "/" . $domainname;
if (\Froxlor\Settings::Get('system.leecc') > 0) {
$certificate_folder .= "_ecc";
}
$certificate_folder = \Froxlor\FileDir::makeCorrectDir($certificate_folder);
$certificate_folder = \Froxlor\Cron\Http\LetsEncrypt\AcmeSh::getWorkingDirFromEnv($domainname);
if (file_exists($certificate_folder)) {
$params = " --remove -d " . $domainname;
if (\Froxlor\Settings::Get('system.leecc') > 0) {

View File

@@ -7,17 +7,17 @@ final class Froxlor
{
// Main version variable
const VERSION = '0.10.4';
const VERSION = '0.10.19';
// Database version (YYYYMMDDC where C is a daily counter)
const DBVERSION = '201910200';
const DBVERSION = '202005150';
// Distribution branding-tag (used for Debian etc.)
const BRANDING = '';
/**
* return path to where froxlor is installed, e.g.
* /var/www/froxlor
* /var/www/froxlor/
*
* @return string
*/

View File

@@ -87,10 +87,13 @@ class FroxlorLogger
self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG));
break;
case 'file':
if (empty(Settings::Get('logger.logfile')) || ! is_writeable(Settings::Get('logger.logfile'))) {
$logger_logfile = Settings::Get('logger.logfile');
// is_writable needs an existing file to check if it's actually writable
@touch($logger_logfile);
if (empty($logger_logfile) || ! is_writable($logger_logfile)) {
Settings::Set('logger.logfile', '/tmp/froxlor.log');
}
self::$ml->pushHandler(new StreamHandler(Settings::Get('logger.logfile'), Logger::DEBUG));
self::$ml->pushHandler(new StreamHandler($logger_logfile, Logger::DEBUG));
break;
case 'mysql':
self::$ml->pushHandler(new MysqlHandler(Logger::DEBUG));

View File

@@ -37,20 +37,31 @@ class Statistics
\Froxlor\FileDir::safe_exec('mkdir -p ' . escapeshellarg(Settings::Get('system.awstats_conf')));
}
$logformat = Settings::Get('system.awstats_logformat');
if (! is_numeric($logformat)) {
// if LogFormat is NOT numeric (e.g. 1,2,3,4), we quote it.
// 1-4 are pre-defined formats by awstats which must not be quoted to work properly. So if
// it is not a integer, it is something customized and we simply quote it.
// Only escaping double-quote should be fine, as we only put the whole string under double-quote.
$logformat = '"' . str_replace('"', '\"', Settings::Get('system.awstats_logformat')) . '"';
}
// These are the variables we will replace
$regex = array(
'/\{LOG_FILE\}/',
'/\{SITE_DOMAIN\}/',
'/\{HOST_ALIASES\}/',
'/\{CUSTOMER_DOCROOT\}/',
'/\{AWSTATS_CONF\}/'
'/\{AWSTATS_CONF\}/',
'/\{AWSTATS_LOGFORMAT\}/'
);
$replace = array(
\Froxlor\FileDir::makeCorrectFile($logFile),
$siteDomain,
$hostAliases,
$awstats_dir,
\Froxlor\FileDir::makeCorrectDir(Settings::Get('system.awstats_conf'))
\Froxlor\FileDir::makeCorrectDir(Settings::Get('system.awstats_conf')),
$logformat
);
// File names

View File

@@ -209,12 +209,12 @@ class MailLogParser
$timestamp = $this->getLogTimestamp($line);
if ($this->startTime < $timestamp) {
if (preg_match("/dovecot.*(?::|\]) imap\(.*@([a-z0-9\.\-]+)\):.*(?:in=(\d+) out=(\d+)|bytes=(\d+)\/(\d+))/i", $line, $matches)) {
if (preg_match("/dovecot.*(?::|\]) imap\(.*@([a-z0-9\.\-]+)\)(<\d+><[a-z0-9+\/=]+>)?:.*(?:in=(\d+) out=(\d+)|bytes=(\d+)\/(\d+))/i", $line, $matches)) {
// Dovecot IMAP
$this->addDomainTraffic($matches[1], (int) $matches[2] + (int) $matches[3], $timestamp);
} elseif (preg_match("/dovecot.*(?::|\]) pop3\(.*@([a-z0-9\.\-]+)\):.*in=(\d+).*out=(\d+)/i", $line, $matches)) {
$this->addDomainTraffic($matches[1], (int) $matches[3] + (int) $matches[4], $timestamp);
} elseif (preg_match("/dovecot.*(?::|\]) pop3\(.*@([a-z0-9\.\-]+)\)(<\d+><[a-z0-9+\/=]+>)?:.*in=(\d+).*out=(\d+)/i", $line, $matches)) {
// Dovecot POP3
$this->addDomainTraffic($matches[1], (int) $matches[2] + (int) $matches[3], $timestamp);
$this->addDomainTraffic($matches[1], (int) $matches[3] + (int) $matches[4], $timestamp);
}
}
}

View File

@@ -4,6 +4,36 @@ namespace Froxlor;
class PhpHelper
{
private static $sort_key = 'id';
private static $sort_type = SORT_STRING;
/**
* sort an array by either natural or string sort and a given index where the value for comparison is found
*
* @param array $list
* @param string $key
*
* @return boolean
*/
public static function sortListBy(&$list, $key = 'id')
{
self::$sort_type = Settings::Get('panel.natsorting') == 1 ? SORT_NATURAL : SORT_STRING;
self::$sort_key = $key;
return usort($list, array(
'self',
'sortListByGivenKey'
));
}
private static function sortListByGivenKey($a, $b)
{
if (self::$sort_type == SORT_NATURAL) {
return strnatcasecmp($a[self::$sort_key], $b[self::$sort_key]);
}
return strcasecmp($a[self::$sort_key], $b[self::$sort_key]);
}
/**
* Wrapper around htmlentities to handle arrays, with the advantage that you
* can select which fields should be handled by htmlentities
@@ -344,7 +374,7 @@ class PhpHelper
$returnval = array();
if (is_array($source)) {
$source = array_map('trim', $source);
$source = array_filter($source, function ($value) {
$returnval = array_filter($source, function ($value) {
return $value !== '';
});
} else {

View File

@@ -12,5 +12,4 @@ class FroxlorVhostSettings
$result = Database::pexecute_first($sel_stmt);
return $result['vcentries'] > 0 ? true : false;
}
}

View File

@@ -242,8 +242,8 @@ class Store
$mysql_access_host_array = array_map('trim', explode(',', Settings::Get('system.mysql_access_host')));
$mysql_access_host_array[] = $newfieldvalue;
$mysql_access_host_array = array_unique(\Froxlor\PhpHelper::arrayTrim($mysql_access_host_array));
$mysql_access_host = implode(',', $mysql_access_host_array);
\Froxlor\Database\DbManager::correctMysqlUsers($mysql_access_host_array);
$mysql_access_host = implode(',', $mysql_access_host_array);
Settings::Set('system.mysql_access_host', $mysql_access_host);
}
@@ -293,9 +293,11 @@ class Store
'cleanMySQLAccessHost'
), $mysql_access_host_array);
$mysql_access_host_array = array_unique($mysql_access_host_array);
$mysql_access_host_array = array_unique(\Froxlor\PhpHelper::arrayTrim($mysql_access_host_array));
$newfieldvalue = implode(',', $mysql_access_host_array);
\Froxlor\Database\DbManager::correctMysqlUsers($mysql_access_host_array);
$mysql_access_host = implode(',', $mysql_access_host_array);
Settings::Set('system.mysql_access_host', $mysql_access_host);
}
return $returnvalue;

View File

@@ -0,0 +1,321 @@
<?php
namespace Froxlor\UI;
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* For the full copyright and license information, please view the COPYING
* file that was distributed with this source code. You can also view the
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
*
* @copyright (c) the authors
* @author Froxlor team <team@froxlor.org> (2010-)
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
* @package API
* @since 0.10.0
*
*/
/**
* Class to manage pagination, limiting and ordering
*/
class Pagination
{
private $data = array();
private $fields = null;
public $sortorder = 'ASC';
public $sortfield = null;
private $searchtext = null;
private $searchfield = null;
private $is_search = false;
private $pageno = 0;
private $entries = 0;
/**
* Create new pagination object to search/filter, limit and sort Api-listing() calls
*
* @param array $userinfo
* @param array $fields
* @param number $total_entries
*/
public function __construct($userinfo, $fields = array(), $total_entries = 0)
{
$this->fields = $fields;
$this->entries = $total_entries;
$this->pageno = 1;
// add default limitation by settings
$this->addLimit(\Froxlor\Settings::Get('panel.paging'));
// check search request
$this->searchtext = '';
if (count($fields) > 0) {
$orderfields = array_keys($fields);
$this->searchfield = $orderfields[0];
}
if (isset($_REQUEST['searchtext']) && (preg_match('/[-_@\p{L}\p{N}*.]+$/u', $_REQUEST['searchtext']) || $_REQUEST['searchtext'] === '')) {
$this->searchtext = trim($_REQUEST['searchtext']);
}
if (isset($_REQUEST['searchfield']) && isset($fields[$_REQUEST['searchfield']])) {
$this->searchfield = $_REQUEST['searchfield'];
}
if (! empty($this->searchtext) && ! empty($this->searchfield)) {
$this->addSearch($this->searchtext, $this->searchfield);
}
// check other ordering requests
if (isset($_REQUEST['sortorder']) && (strtolower($_REQUEST['sortorder']) == 'desc' || strtolower($_REQUEST['sortorder']) == 'asc')) {
$this->sortorder = strtoupper($_REQUEST['sortorder']);
}
if (isset($_REQUEST['sortfield']) && isset($fields[$_REQUEST['sortfield']])) {
$this->sortfield = $_REQUEST['sortfield'];
$this->addOrderBy($this->sortfield, $this->sortorder);
} else {
// add default ordering by given fields
if (count($fields) > 0) {
$orderfields = array_keys($fields);
$this->sortfield = $orderfields[0];
$this->addOrderBy($orderfields[0], $this->sortorder);
}
}
// check current page / pages
if (isset($_REQUEST['pageno']) && intval($_REQUEST['pageno']) != 0) {
$this->pageno = intval($_REQUEST['pageno']);
}
if (($this->pageno - 1) * \Froxlor\Settings::Get('panel.paging') > $this->entries) {
$this->pageno = 1;
}
$this->addOffset(($this->pageno - 1) * \Froxlor\Settings::Get('panel.paging'));
}
/**
* add a field for ordering
*
* @param string $field
* @param string $order
* optional, default 'ASC'
*
* @return \Froxlor\UI\Pagination
*/
public function addOrderBy($field = null, $order = 'ASC')
{
if (! isset($this->data['sql_orderby'])) {
$this->data['sql_orderby'] = array();
}
$this->data['sql_orderby'][$field] = $order;
return $this;
}
/**
* add a limit
*
* @param number $limit
* optional, default 0
*
* @return \Froxlor\UI\Pagination
*/
public function addLimit($limit = 0)
{
$this->data['sql_limit'] = (int) $limit;
return $this;
}
/**
* add an offset
*
* @param number $offset
* optional, default 0
*
* @return \Froxlor\UI\Pagination
*/
public function addOffset($offset = 0)
{
$this->data['sql_offset'] = (int) $offset;
return $this;
}
/**
* add a search operation
*
* @param string $searchtext
* @param string $field
* @param string $operator
*
* @return \Froxlor\UI\Pagination
*/
public function addSearch($searchtext = null, $field = null, $operator = null)
{
if (! isset($this->data['sql_search'])) {
$this->data['sql_search'] = array();
}
$this->data['sql_search'][$field] = [
'value' => $searchtext,
'op' => $operator
];
// if a search is performed, the result-entries-count is irrelevant
// we do not want pagination
$this->is_search = true;
return $this;
}
/**
* return number of total entries the user can access from the current resource
*
* @return number
*/
public function getEntries()
{
return $this->entries;
}
/**
* Returns html code for sorting field
*
* @param array $lng
* Language array
* @return string the html sortcode
*/
public function getHtmlSortCode($lng, $break = false)
{
$sortcode = '';
$fieldoptions = '';
$orderoptions = '';
foreach ($this->fields as $fieldname => $fieldcaption) {
$fieldoptions .= HTML::makeoption($fieldcaption, $fieldname, $this->sortfield, true, true);
}
$breakorws = ($break ? '<br />' : '&nbsp;');
foreach (array(
'asc' => $lng['panel']['ascending'],
'desc' => $lng['panel']['descending']
) as $sortordertype => $sortorderdescription) {
$orderoptions .= HTML::makeoption($sortorderdescription, $sortordertype, $this->sortorder, true, true);
}
eval("\$sortcode =\"" . Template::getTemplate("misc/htmlsortcode", '1') . "\";");
return $sortcode;
}
/**
* Returns html code for sorting arrows
*
* @param string $baseurl
* URL to use as base for links
* @param string $field
* If set, only this field will be returned
*
* @return mixed An array or a string (if field is set) of html code of arrows
*/
public function getHtmlArrowCode($baseurl, $field = '')
{
global $theme;
if ($field != '' && isset($this->fields[$field])) {
$baseurl = htmlspecialchars($baseurl);
$fieldname = htmlspecialchars($field);
eval("\$arrowcode =\"" . Template::getTemplate("misc/htmlarrowcode", '1') . "\";");
} else {
$baseurl = htmlspecialchars($baseurl);
$arrowcode = array();
foreach ($this->fields as $fieldname => $fieldcaption) {
$fieldname = htmlspecialchars($fieldname);
eval("\$arrowcode[\$fieldname] =\"" . Template::getTemplate("misc/htmlarrowcode", '1') . "\";");
}
}
return $arrowcode;
}
/**
* Returns html code for searching field
*
* @param array $lng
* Language array
*
* @return string the html searchcode
*/
public function getHtmlSearchCode($lng)
{
$searchcode = '';
$fieldoptions = '';
$searchtext = htmlspecialchars($this->searchtext);
foreach ($this->fields as $fieldname => $fieldcaption) {
$fieldoptions .= HTML::makeoption($fieldcaption, $fieldname, $this->searchfield, true, true);
}
eval("\$searchcode =\"" . Template::getTemplate("misc/htmlsearchcode", '1') . "\";");
return $searchcode;
}
/**
* Returns html code for paging
*
* @param string $baseurl
* URL to use as base for links
*
* @return string the html pagingcode
*/
public function getHtmlPagingCode($baseurl)
{
if (\Froxlor\Settings::Get('panel.paging') == 0 || $this->is_search) {
return '';
} else {
$pages = intval($this->getEntries() / \Froxlor\Settings::Get('panel.paging'));
}
if ($this->getEntries() % \Froxlor\Settings::Get('panel.paging') != 0) {
$pages ++;
}
if ($pages > 1) {
$start = $this->pageno - 4;
if ($start < 1) {
$start = 1;
}
$stop = $this->pageno + 4;
if ($stop > $pages) {
$stop = $pages;
}
// check for possible sorting values and keep it
$orderstr = '';
if (!empty($this->sortfield)) {
$fieldname = htmlspecialchars($this->sortfield);
$orderstr .= '&amp;sortfield=' . $fieldname . '&amp;sortorder=' . $this->sortorder;
}
$pagingcode = '<a href="' . htmlspecialchars($baseurl) . '&amp;pageno=1' . $orderstr . '">&laquo;</a> <a href="' . htmlspecialchars($baseurl) . '&amp;pageno=' . ((intval($this->pageno) - 1) == 0 ? '1' : intval($this->pageno) - 1) . $orderstr . '">&lt;</a>&nbsp;';
for ($i = $start; $i <= $stop; $i ++) {
if ($i != $this->pageno) {
$pagingcode .= ' <a href="' . htmlspecialchars($baseurl) . '&amp;pageno=' . $i . $orderstr . '">' . $i . '</a>&nbsp;';
} else {
$pagingcode .= ' <strong>' . $i . '</strong>&nbsp;';
}
}
$pagingcode .= ' <a href="' . htmlspecialchars($baseurl) . '&amp;pageno=' . ((intval($this->pageno) + 1) > $pages ? $pages : intval($this->pageno) + 1) . $orderstr . '">&gt;</a> <a href="' . $baseurl . '&amp;pageno=' . $pages . $orderstr . '">&raquo;</a>';
} else {
$pagingcode = '';
}
return $pagingcode;
}
/**
* return parameter array for API command parameters $sql_search, $sql_limit, $sql_offset and $sql_orderby
*
* @return array
*/
public function getApiCommandParams()
{
return $this->data;
}
}

View File

@@ -79,8 +79,8 @@ class User
/**
* Function which updates all counters of used ressources in panel_admins and panel_customers
*
* @param
* bool Set to true to get an array with debug information
* @param bool $returndebuginfo
* Set to true to get an array with debug information
* @return array Contains debug information if parameter 'returndebuginfo' is set to true
*
* @author Florian Lippert <flo@syscp.org> (2003-2009)
@@ -100,17 +100,17 @@ class User
// Customers
$customers_stmt = Database::prepare('SELECT * FROM `' . TABLE_PANEL_CUSTOMERS . '` ORDER BY `customerid`');
Database::pexecute($customers_stmt);
// array to store currently used resources per admin
$admin_resources = array();
while ($customer = $customers_stmt->fetch(\PDO::FETCH_ASSOC)) {
// set current admin
$cur_adm = $customer['adminid'];
// initialize admin-resources array for admin $customer['adminid']
if (! isset($admin_resources[$cur_adm])) {
$admin_resources[$cur_adm] = array();
}
// fill admin resource usage array with customer data
self::addResourceCountEx($admin_resources[$cur_adm], $customer, 'diskspace_used', 'diskspace');
self::addResourceCountEx($admin_resources[$cur_adm], $customer, 'traffic_used', 'traffic_used'); // !!! yes, USED and USED
@@ -126,6 +126,7 @@ class User
self::addResourceCount($admin_resources[$cur_adm], $customer, $field . '_used', $field);
}
// calculate real usage
$customer_mysqls_stmt = Database::prepare('SELECT COUNT(*) AS `number_mysqls` FROM `' . TABLE_PANEL_DATABASES . '`
WHERE `customerid` = :cid');
$customer_mysqls = Database::pexecute_first($customer_mysqls_stmt, array(
@@ -181,6 +182,7 @@ class User
));
$customer['email_quota_used_new'] = (int) $customer_email_quota['email_quota'];
// update database accordingly
$stmt = Database::prepare('UPDATE `' . TABLE_PANEL_CUSTOMERS . '`
SET `mysqls_used` = :mysqls_used,
`emails_used` = :emails_used,
@@ -211,63 +213,56 @@ class User
$admins_stmt = Database::prepare('SELECT * FROM `' . TABLE_PANEL_ADMINS . '` ORDER BY `adminid`');
Database::pexecute($admins_stmt, array());
while ($admin = $admins_stmt->fetch(\PDO::FETCH_ASSOC)) {
$resource_fields = array(
'diskspace_used',
'traffic_used',
'mysqls_used',
'ftps_used',
'emails_used',
'email_accounts_used',
'email_forwarders_used',
'email_quota_used',
'subdomains_used'
);
$admin_customers_stmt = Database::prepare('SELECT * FROM `' . TABLE_PANEL_CUSTOMERS . '` WHERE `adminid` = :aid');
while ($admin = $admins_stmt->fetch(\PDO::FETCH_ASSOC)) {
Database::pexecute($admin_customers_stmt, array(
"aid" => $admin['adminid']
));
$admin_customers = $admin_customers_stmt->fetchAll(\PDO::FETCH_ASSOC);
$admin['customers_used_new'] = count($admin_customers);
$admin_domains_stmt = Database::prepare('SELECT COUNT(*) AS `number_domains` FROM `' . TABLE_PANEL_DOMAINS . '` WHERE `adminid` = :aid');
$admin_domains_stmt = Database::prepare('SELECT COUNT(*) AS `number_domains` FROM `' . TABLE_PANEL_DOMAINS . '` WHERE `adminid` = :aid AND `parentdomainid` = "0"');
$admin_domains = Database::pexecute_first($admin_domains_stmt, array(
"aid" => $admin['adminid']
));
// substract the amount of domains that are std-subdomains later when we iterated through all customers and now for sure
// substract the amount of domains that are std-subdomains later when we iterated through all customers and know for sure
$admin['domains_used_new'] = $admin_domains['number_domains'];
// set current admin
$cur_adm = $admin['adminid'];
// if there's an admin without any customers it might be possible that the id is not yet known in $admin_resources
if (! isset($admin_resources[$cur_adm])) {
$admin_resources[$cur_adm] = array();
}
foreach (array(
'diskspace_used',
'traffic_used',
'mysqls_used',
'ftps_used',
'emails_used',
'email_accounts_used',
'email_forwarders_used',
'email_quota_used',
'subdomains_used'
) as $field) {
// be sure that all fields are set in the array
foreach ($resource_fields as $field) {
self::initArrField($field, $admin_resources[$cur_adm], 0);
$admin[$field . '_new'] = $admin_resources[$cur_adm][$field];
// initialize new values
$admin[$field . '_new'] = 0;
}
// now get the customer resource usage which we have re-calculated previously
foreach ($admin_customers as $acustomer) {
foreach (array(
'diskspace_used',
'traffic_used',
'mysqls_used',
'ftps_used',
'emails_used',
'email_accounts_used',
'email_forwarders_used',
'email_quota_used',
'subdomains_used'
) as $field) {
foreach ($resource_fields as $field) {
$admin[$field . '_new'] += $acustomer[$field];
}
// check for std-subdomain
if ($acustomer['standardsubdomain'] > 0) {
// std-subdomain does not count to assign resource
// std-subdomain does not count as assigned resource
$admin['domains_used_new'] --;
}
}
// update database entry accordingly
$stmt = Database::prepare('UPDATE `' . TABLE_PANEL_ADMINS . '`
SET `customers_used` = :customers_used,
`domains_used` = :domains_used,

View File

@@ -4625,11 +4625,11 @@ aliases: files
<command><![CDATA[useradd -s /bin/false -g {{settings.system.mod_fcgid_httpgroup}} {{settings.system.mod_fcgid_httpuser}}]]></command>
<command><![CDATA[mkdir -p {{settings.system.mod_fcgid_configdir}}]]></command>
<command><![CDATA[mkdir -p {{settings.system.mod_fcgid_tmpdir}}]]></command>
<command><![CDATA[a2dismod php7.0]]></command>
<command><![CDATA[a2dismod php7.2]]></command>
</commands>
<!-- instead of just restarting apache, we let the cronjob do all the
dirty work -->
<command><![CDATA[php {{const.\Froxlor\Froxlor::getInstallDir()}}/scripts/froxlor_master_cronjob.php --force]]></command>
<command><![CDATA[php {{const.install_dir}}scripts/froxlor_master_cronjob.php --force]]></command>
</daemon>
<!-- PHP-FPM -->
<daemon name="php-fpm"
@@ -4667,7 +4667,7 @@ aliases: files
</commands>
<!-- instead of just restarting apache, we let the cronjob do all the
dirty work -->
<command><![CDATA[php {{const.\Froxlor\Froxlor::getInstallDir()}}/scripts/froxlor_master_cronjob.php --force]]></command>
<command><![CDATA[php {{const.install_dir}}scripts/froxlor_master_cronjob.php --force]]></command>
</daemon>
</service>
</services>

View File

@@ -4827,11 +4827,11 @@ aliases: files
<command><![CDATA[useradd -s /bin/false -g {{settings.system.mod_fcgid_httpgroup}} {{settings.system.mod_fcgid_httpuser}}]]></command>
<command><![CDATA[mkdir -p {{settings.system.mod_fcgid_configdir}}]]></command>
<command><![CDATA[mkdir -p {{settings.system.mod_fcgid_tmpdir}}]]></command>
<command><![CDATA[a2dismod php7.0]]></command>
<command><![CDATA[a2dismod php7.3]]></command>
</commands>
<!-- instead of just restarting apache, we let the cronjob do all the
dirty work -->
<command><![CDATA[php {{const.\Froxlor\Froxlor::getInstallDir()}}/scripts/froxlor_master_cronjob.php --force]]></command>
<command><![CDATA[php {{const.install_dir}}scripts/froxlor_master_cronjob.php --force]]></command>
</daemon>
<!-- PHP-FPM -->
<daemon name="php-fpm"
@@ -4860,7 +4860,7 @@ aliases: files
</visibility>
<visibility mode="true">{{settings.phpfpm.enabled_ownvhost}}
</visibility>
<command><![CDATA[a2dismod php7.0]]></command>
<command><![CDATA[a2dismod php7.3]]></command>
</commands>
<commands index="5">
<visibility mode="equals" value="apache2">{{settings.system.webserver}}
@@ -4869,7 +4869,7 @@ aliases: files
</commands>
<!-- instead of just restarting apache, we let the cronjob do all the
dirty work -->
<command><![CDATA[php {{const.\Froxlor\Froxlor::getInstallDir()}}/scripts/froxlor_master_cronjob.php --force]]></command>
<command><![CDATA[php {{const.install_dir}}scripts/froxlor_master_cronjob.php --force]]></command>
</daemon>
</service>
</services>

View File

@@ -1,7 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<froxlor>
<distribution name="RHEL / CentOS" version="7"
<distribution name="CentOS" version="7"
defaulteditor="/usr/bin/nano">
<defaults>
<property>
<varname>apacheconf_vhost</varname>
<settinggroup>system</settinggroup>
<value>/etc/httpd/conf.d/</value>
</property>
<property>
<varname>apacheconf_diroptions</varname>
<settinggroup>system</settinggroup>
<value>/etc/httpd/conf.d/</value>
</property>
<property>
<varname>apacheconf_htpasswddir</varname>
<settinggroup>system</settinggroup>
<value>/etc/httpd/froxlor-htpasswd/</value>
</property>
<property>
<varname>apachereload_command</varname>
<settinggroup>system</settinggroup>
<value>systemctl reload-or-restart httpd.service</value>
</property>
<property>
<varname>bindreload_command</varname>
<settinggroup>system</settinggroup>
<value>systemctl reload-or-restart named.service</value>
</property>
<property>
<varname>crondreload</varname>
<settinggroup>system</settinggroup>
<value>systemctl reload-or-restart crond.service</value>
</property>
</defaults>
<services>
<!-- HTTP -->
<service type="http" title="{{lng.admin.configfiles.http}}">
@@ -61,6 +93,20 @@ Alias "/.well-known/acme-challenge" "{{settings.system.letsencryptchallengepath}
<command><![CDATA[systemctl reload-or-restart httpd.service]]></command>
</daemon>
</service>
<!--DNS -->
<service type="dns" title="{{lng.admin.configfiles.dns}}">
<!--Bind9 -->
<daemon name="bind" title="Bind9 nameserver" default="true">
<install><![CDATA[yum install bind]]></install>
<command><![CDATA[ln -sv /etc/named /etc/bind]]></command>
<command><![CDATA[echo "include \"/etc/named.conf.local\";" >> /etc/named.conf]]></command>
<command><![CDATA[echo "include \"{{settings.system.bindconf_directory}}froxlor_bind.conf\";" >> /etc/named.conf.local]]></command>
<command><![CDATA[touch {{settings.system.bindconf_directory}}froxlor_bind.conf]]></command>
<command><![CDATA[chown named:0 {{settings.system.bindconf_directory}}froxlor_bind.conf]]></command>
<command><![CDATA[chmod 0644 {{settings.system.bindconf_directory}}froxlor_bind.conf]]></command>
<command><![CDATA[systemctl restart named]]></command>
</daemon>
</service>
<!-- SMTP services -->
<service type="smtp" title="{{lng.admin.configfiles.smtp}}">
<!-- general SMTP commands -->
@@ -1825,6 +1871,7 @@ iterate_query = SELECT username AS user FROM mail_users
<!-- Proftpd -->
<daemon name="proftpd" version="1.3" title="ProFTPd"
default="true">
<install><![CDATA[yum --enablerepo=extras install epel-release]]></install>
<install><![CDATA[yum install proftpd proftpd-mysql]]></install>
<file name="/etc/proftpd.conf" chown="root:0"
chmod="0600" backup="true">
@@ -2295,9 +2342,10 @@ ControlsLog /var/log/proftpd/controls.log
<!-- AWstats -->
<daemon name="awstats"
title="Awstats (webalizer alternative)">
<install><![CDATA[yum install awstats]]></install>
<command><![CDATA[sed -i.bak 's/^DirData/# DirData/' {{settings.system.awstats_conf}}/awstats.model.conf]]></command>
<command><![CDATA[sed -i.bak 's|^\\(DirIcons=\\).*$|\\1\\"/awstats-icon\\"|' {{settings.system.awstats_conf}}/awstats.model.conf]]></command>
<command><![CDATA[rm /etc/cron.d/awstats]]></command>
<command><![CDATA[rm /etc/cron.hourly/awstats]]></command>
</daemon>
<!-- libnss-mysql -->
<daemon name="libnss"

2484
lib/configfiles/centos8.xml Normal file

File diff suppressed because it is too large Load Diff

4100
lib/configfiles/focal.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3825,7 +3825,7 @@ aliases: files
</commands>
<!-- instead of just restarting apache, we let the cronjob do all the
dirty work -->
<command><![CDATA[php {{const.\Froxlor\Froxlor::getInstallDir()}}/scripts/froxlor_master_cronjob.php --force]]></command>
<command><![CDATA[php {{const.install_dir}}scripts/froxlor_master_cronjob.php --force]]></command>
</daemon>
<!-- PHP-FPM -->
<daemon name="php-fpm"
@@ -3864,7 +3864,7 @@ aliases: files
</commands>
<!-- instead of just restarting apache, we let the cronjob do all the
dirty work -->
<command><![CDATA[php {{const.\Froxlor\Froxlor::getInstallDir()}}/scripts/froxlor_master_cronjob.php --force]]></command>
<command><![CDATA[php {{const.install_dir}}scripts/froxlor_master_cronjob.php --force]]></command>
</daemon>
</service>
</services>

Some files were not shown because too many files have changed in this diff Show More