Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 305f3f6f86 | |||
|
|
22aa197864 | ||
|
|
d53f9b8e58 | ||
|
|
9d4205acf6 | ||
|
|
cb8b969ddd | ||
|
|
fcfd44f726 | ||
|
|
52a06bf806 | ||
|
|
20aa162fcc | ||
|
|
bb60df0709 | ||
|
|
a86c8535e0 | ||
|
|
ab82695806 | ||
|
|
c52d9bbd03 | ||
|
|
d1043b4645 | ||
|
|
9d113afc83 | ||
|
|
bbd1dca30e | ||
|
|
6d42968d1a | ||
|
|
8d66a4aec4 | ||
|
|
e071365cd6 | ||
|
|
5f05478c76 | ||
|
|
6616bd9a38 | ||
|
|
947df2079f | ||
|
|
b791cd5c3e | ||
|
|
1662745991 | ||
|
|
067c9f8c76 | ||
|
|
f396bd5184 | ||
|
|
03b5a921ff | ||
|
|
e357f7e9c3 | ||
|
|
da7309c41e | ||
|
|
257ef4c059 | ||
|
|
eda8700217 | ||
|
|
94d9c3eedf | ||
|
|
f9f1048477 | ||
|
|
a2fca3fe69 | ||
|
|
105213fd3f | ||
|
|
07f4491db6 | ||
|
|
e0fa64f897 | ||
|
|
ed72fd1766 | ||
|
|
8a30bc07f5 | ||
|
|
ddcd55a83d | ||
|
|
c3205d3672 | ||
|
|
c668c180d5 | ||
|
|
1cf5865bba | ||
|
|
6f5e49de79 | ||
|
|
a9c613e71c | ||
|
|
981d7f3d9a | ||
|
|
3445472049 | ||
|
|
bfc816a51e | ||
|
|
5afe5a8c46 | ||
|
|
eb9dded947 | ||
|
|
e958cfed84 | ||
|
|
5181602921 | ||
|
|
4bfed71ac9 | ||
|
|
69c58d21be | ||
|
|
94051dc9eb | ||
|
|
2ec039372d | ||
|
|
0c3ac31231 | ||
|
|
03257f04cb | ||
|
|
6e37b55ac6 | ||
|
|
196ef9378a | ||
|
|
9ed45ea7f8 | ||
|
|
20755bcead | ||
|
|
bde19997ba | ||
|
|
981d819fd7 | ||
|
|
826ae36647 | ||
|
|
9ddf24539e | ||
|
|
c079047180 | ||
|
|
e1e7bc7b42 | ||
|
|
3940c1429d | ||
|
|
c236d9eaab | ||
|
|
512a544dd1 | ||
|
|
688994e40c | ||
|
|
0fb338b32d | ||
|
|
9facaee809 | ||
|
|
e90dae186b | ||
|
|
a7dd5f4685 | ||
|
|
ca5f36d912 | ||
|
|
63d81201de | ||
|
|
0b685d569f | ||
|
|
426f204473 | ||
|
|
84599011cf | ||
|
|
6202e24b77 | ||
|
|
8deaf6a013 | ||
|
|
a491667ce5 | ||
|
|
da810ea953 | ||
|
|
d51556f918 | ||
|
|
51b6e067e8 | ||
|
|
233bf27afe | ||
|
|
09b3c1c45a | ||
|
|
2e6b939ec6 | ||
|
|
c1f03c1683 | ||
|
|
5731f5ffff | ||
|
|
34cf6698bc | ||
|
|
4642160724 | ||
|
|
78a259ef3b | ||
|
|
68cf4ab69a | ||
|
|
d5661d492d | ||
|
|
6900898ae1 | ||
|
|
d90fb7fa68 | ||
|
|
4ea8629fcc | ||
|
|
9d4ff8698d | ||
|
|
b164038846 | ||
|
|
5c46960734 | ||
|
|
a7f4f0c737 | ||
|
|
b64dd501dd | ||
|
|
1679675aa1 | ||
|
|
640466f301 | ||
|
|
9c9771a371 | ||
|
|
1922b3ce65 | ||
|
|
83e819908a | ||
|
|
0924aa644b | ||
|
|
7711ce1d66 | ||
|
|
7dae63e586 | ||
|
|
1bcaa45492 | ||
|
|
66cb114f0d | ||
|
|
1c5d60dcfd | ||
|
|
b6da6356fc | ||
|
|
c09670cc45 | ||
|
|
464f5b7bed | ||
|
|
c799235c24 | ||
|
|
a2860e70a5 | ||
|
|
95a96d46a6 | ||
|
|
81f3dbda31 | ||
|
|
4eb4191843 | ||
|
|
ca433d8a61 | ||
|
|
8f4dfe1514 | ||
|
|
ee42f5168e | ||
|
|
fc8ca57f8c | ||
|
|
7e4bba2d55 | ||
|
|
7e635f9be4 | ||
|
|
e9406a20f2 | ||
|
|
de7729cec8 | ||
|
|
d60e48849b | ||
|
|
908df5a7bb | ||
|
|
c1952afb94 | ||
|
|
7a22e8f4dd | ||
|
|
3ac0da2cdd | ||
|
|
eb816c4cc6 | ||
|
|
64d8bf4fba | ||
|
|
ae6ee95973 | ||
|
|
e9051dc30a | ||
|
|
b6c7c53c3a | ||
|
|
f36bc61fc7 | ||
|
|
c56e0b9dac | ||
|
|
1deb08bf75 | ||
|
|
b30d7a8252 | ||
|
|
b03e11c18d | ||
|
|
bf7d22a794 | ||
|
|
fb57a8a3b5 | ||
|
|
0d625797b0 | ||
|
|
6777fbf229 | ||
|
|
23f1f79eff | ||
|
|
a5af104d53 |
40
.drone.yml
Normal file
40
.drone.yml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
kind: pipeline
|
||||||
|
name: deploy-froxlor
|
||||||
|
type: docker
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: arm64
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- 2.1.x
|
||||||
|
event:
|
||||||
|
include:
|
||||||
|
- push
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: deploy
|
||||||
|
image: cr.wks/drone/drone-rsync:latest
|
||||||
|
settings:
|
||||||
|
hosts: ["rechner02.maketank.net"]
|
||||||
|
source: ./
|
||||||
|
target: ~/froxlor-test
|
||||||
|
user: www-data
|
||||||
|
exclude: ['vendor', '.git*', '*drone.yml', '.settings', '.buildpath', '.editorconfig', '.project', '.travis.yml']
|
||||||
|
args: '-v --delete'
|
||||||
|
log_level: quiet
|
||||||
|
key:
|
||||||
|
from_secret: ssh-www-data-maketank-rsa
|
||||||
|
command_timeout: 10m
|
||||||
|
- name: compose-install
|
||||||
|
image: appleboy/drone-ssh
|
||||||
|
settings:
|
||||||
|
host:
|
||||||
|
- rechner02.maketank.net
|
||||||
|
username: www-data
|
||||||
|
key:
|
||||||
|
from_secret: ssh-www-data-maketank-rsa
|
||||||
|
script:
|
||||||
|
- cd ~/froxlor-test && composer install --no-dev
|
||||||
|
|
||||||
2
.github/workflows/build-docs.yml
vendored
2
.github/workflows/build-docs.yml
vendored
@@ -11,4 +11,4 @@ jobs:
|
|||||||
- env:
|
- env:
|
||||||
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
gh workflow run --repo Froxlor/Documentation build-and-deploy -f type=tags ref=${{github.ref_name}}
|
gh workflow run --repo Froxlor/Documentation build-and-deploy.yml -f type=tags ref=${{github.ref_name}}
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,6 +13,7 @@ logs/*
|
|||||||
*~
|
*~
|
||||||
.well-known
|
.well-known
|
||||||
.idea
|
.idea
|
||||||
|
.DS_Store
|
||||||
*.iml
|
*.iml
|
||||||
img/
|
img/
|
||||||
vendor/
|
vendor/
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ return [
|
|||||||
'extras.directoryprotection' => lng('menue.extras.extras') . " / " . lng('menue.extras.directoryprotection'),
|
'extras.directoryprotection' => lng('menue.extras.extras') . " / " . lng('menue.extras.directoryprotection'),
|
||||||
'extras.pathoptions' => lng('menue.extras.extras') . " / " . lng('menue.extras.pathoptions'),
|
'extras.pathoptions' => lng('menue.extras.extras') . " / " . lng('menue.extras.pathoptions'),
|
||||||
'extras.logger' => lng('menue.extras.extras') . " / " . lng('menue.logger.logger'),
|
'extras.logger' => lng('menue.extras.extras') . " / " . lng('menue.logger.logger'),
|
||||||
'extras.backup' => lng('menue.extras.extras') . " / " . lng('menue.extras.backup'),
|
'extras.export' => lng('menue.extras.extras') . " / " . lng('menue.extras.export'),
|
||||||
'traffic' => lng('menue.traffic.traffic'),
|
'traffic' => lng('menue.traffic.traffic'),
|
||||||
'traffic.http' => lng('menue.traffic.traffic') . " / HTTP",
|
'traffic.http' => lng('menue.traffic.traffic') . " / HTTP",
|
||||||
'traffic.ftp' => lng('menue.traffic.traffic') . " / FTP",
|
'traffic.ftp' => lng('menue.traffic.traffic') . " / FTP",
|
||||||
|
|||||||
@@ -138,6 +138,26 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
|
'system_req_limit_per_interval' => [
|
||||||
|
'label' => lng('serversettings.req_limit_per_interval'),
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'req_limit_per_interval',
|
||||||
|
'type' => 'number',
|
||||||
|
'min' => 30,
|
||||||
|
'default' => 60,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'advanced_mode' => true
|
||||||
|
],
|
||||||
|
'system_req_limit_interval' => [
|
||||||
|
'label' => lng('serversettings.req_limit_interval'),
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'req_limit_interval',
|
||||||
|
'type' => 'number',
|
||||||
|
'min' => 5,
|
||||||
|
'default' => 60,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'advanced_mode' => true
|
||||||
|
],
|
||||||
'customer_accountprefix' => [
|
'customer_accountprefix' => [
|
||||||
'label' => lng('serversettings.accountprefix'),
|
'label' => lng('serversettings.accountprefix'),
|
||||||
'settinggroup' => 'customer',
|
'settinggroup' => 'customer',
|
||||||
@@ -210,13 +230,13 @@ return [
|
|||||||
'onlyif' => 1
|
'onlyif' => 1
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_backupenabled' => [
|
'system_exportenabled' => [
|
||||||
'label' => lng('serversettings.backupenabled'),
|
'label' => lng('serversettings.exportenabled'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'backupenabled',
|
'varname' => 'exportenabled',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'cronmodule' => 'froxlor/backup',
|
'cronmodule' => 'froxlor/export',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_createstdsubdom_default' => [
|
'system_createstdsubdom_default' => [
|
||||||
|
|||||||
@@ -107,7 +107,8 @@ return [
|
|||||||
'varname' => 'enabled',
|
'varname' => 'enabled',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'api_customer_default' => [
|
'api_customer_default' => [
|
||||||
'label' => lng('serversettings.api_customer_default'),
|
'label' => lng('serversettings.api_customer_default'),
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ return [
|
|||||||
'string_regexp' => '/^(([a-z0-9\-\._]+, ?)*[a-z0-9\-\._]+)?$/i',
|
'string_regexp' => '/^(([a-z0-9\-\._]+, ?)*[a-z0-9\-\._]+)?$/i',
|
||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingClearCertificates',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ return [
|
|||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
||||||
'default' => '/usr/bin/nice -n 5 /usr/bin/php -q',
|
'default' => '/usr/bin/nice -n 5 /usr/bin/php -q',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_crondreload' => [
|
'system_crondreload' => [
|
||||||
'label' => lng('serversettings.system_crondreload'),
|
'label' => lng('serversettings.system_crondreload'),
|
||||||
@@ -55,7 +56,8 @@ return [
|
|||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
||||||
'default' => '/etc/init.d/cron reload',
|
'default' => '/etc/init.d/cron reload',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_cron_allowautoupdate' => [
|
'system_cron_allowautoupdate' => [
|
||||||
'label' => lng('serversettings.system_cron_allowautoupdate'),
|
'label' => lng('serversettings.system_cron_allowautoupdate'),
|
||||||
@@ -63,7 +65,8 @@ return [
|
|||||||
'varname' => 'cron_allowautoupdate',
|
'varname' => 'cron_allowautoupdate',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -181,7 +181,8 @@ return [
|
|||||||
'label' => lng('serversettings.logfiles_format'),
|
'label' => lng('serversettings.logfiles_format'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'logfiles_format',
|
'varname' => 'logfiles_format',
|
||||||
'type' => 'text',
|
'type' => (strpos(Settings::Get('system.logfiles_format'), '"') !== false ? 'textarea' : 'text'),
|
||||||
|
'string_regexp' => '/^[^\0\r\n<>]*$/i',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
@@ -307,7 +308,8 @@ return [
|
|||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
||||||
'default' => '/etc/init.d/apache2 reload',
|
'default' => '/etc/init.d/apache2 reload',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_phpreload_command' => [
|
'system_phpreload_command' => [
|
||||||
'label' => lng('serversettings.phpreload_command'),
|
'label' => lng('serversettings.phpreload_command'),
|
||||||
@@ -319,7 +321,8 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'websrv_avail' => [
|
'websrv_avail' => [
|
||||||
'nginx'
|
'nginx'
|
||||||
]
|
],
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_nginx_php_backend' => [
|
'system_nginx_php_backend' => [
|
||||||
'label' => lng('serversettings.nginx_php_backend'),
|
'label' => lng('serversettings.nginx_php_backend'),
|
||||||
|
|||||||
@@ -157,7 +157,8 @@ return [
|
|||||||
'string_type' => 'file',
|
'string_type' => 'file',
|
||||||
'default' => '/root/.acme.sh/acme.sh',
|
'default' => '/root/.acme.sh/acme.sh',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_letsencryptacmeconf' => [
|
'system_letsencryptacmeconf' => [
|
||||||
'label' => lng('serversettings.letsencryptacmeconf'),
|
'label' => lng('serversettings.letsencryptacmeconf'),
|
||||||
|
|||||||
@@ -126,7 +126,8 @@ return [
|
|||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'phpfpm_ini_values' => [
|
'phpfpm_ini_values' => [
|
||||||
'label' => lng('phpfpm.ini_values'),
|
'label' => lng('phpfpm.ini_values'),
|
||||||
@@ -135,7 +136,8 @@ return [
|
|||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'phpfpm_ini_admin_flags' => [
|
'phpfpm_ini_admin_flags' => [
|
||||||
'label' => lng('phpfpm.ini_admin_flags'),
|
'label' => lng('phpfpm.ini_admin_flags'),
|
||||||
@@ -144,7 +146,8 @@ return [
|
|||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'phpfpm_ini_admin_values' => [
|
'phpfpm_ini_admin_values' => [
|
||||||
'label' => lng('phpfpm.ini_admin_values'),
|
'label' => lng('phpfpm.ini_admin_values'),
|
||||||
@@ -153,7 +156,8 @@ return [
|
|||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -80,7 +80,8 @@ return [
|
|||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
||||||
'default' => '/etc/init.d/bind9 reload',
|
'default' => '/etc/init.d/bind9 reload',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_nameservers' => [
|
'system_nameservers' => [
|
||||||
'label' => lng('serversettings.nameservers'),
|
'label' => lng('serversettings.nameservers'),
|
||||||
@@ -111,7 +112,8 @@ return [
|
|||||||
'string_delimiter' => ',',
|
'string_delimiter' => ',',
|
||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_powerdns_mode' => [
|
'system_powerdns_mode' => [
|
||||||
'label' => lng('serversettings.powerdns_mode'),
|
'label' => lng('serversettings.powerdns_mode'),
|
||||||
|
|||||||
@@ -137,7 +137,8 @@ return [
|
|||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
||||||
'default' => '/etc/init.d/dkim-filter restart',
|
'default' => '/etc/init.d/dkim-filter restart',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ return [
|
|||||||
'varname' => 'unix_names',
|
'varname' => 'unix_names',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => true,
|
'default' => true,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_mailpwcleartext' => [
|
'system_mailpwcleartext' => [
|
||||||
'label' => lng('serversettings.mailpwcleartext'),
|
'label' => lng('serversettings.mailpwcleartext'),
|
||||||
@@ -46,7 +47,8 @@ return [
|
|||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_passwordcryptfunc' => [
|
'system_passwordcryptfunc' => [
|
||||||
'label' => lng('serversettings.passwordcryptfunc'),
|
'label' => lng('serversettings.passwordcryptfunc'),
|
||||||
@@ -59,7 +61,8 @@ return [
|
|||||||
'getAvailablePasswordHashes'
|
'getAvailablePasswordHashes'
|
||||||
],
|
],
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_allow_error_report_admin' => [
|
'system_allow_error_report_admin' => [
|
||||||
'label' => lng('serversettings.allow_error_report_admin'),
|
'label' => lng('serversettings.allow_error_report_admin'),
|
||||||
@@ -67,7 +70,8 @@ return [
|
|||||||
'varname' => 'allow_error_report_admin',
|
'varname' => 'allow_error_report_admin',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_allow_error_report_customer' => [
|
'system_allow_error_report_customer' => [
|
||||||
'label' => lng('serversettings.allow_error_report_customer'),
|
'label' => lng('serversettings.allow_error_report_customer'),
|
||||||
@@ -75,7 +79,8 @@ return [
|
|||||||
'varname' => 'allow_error_report_customer',
|
'varname' => 'allow_error_report_customer',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_allow_customer_shell' => [
|
'system_allow_customer_shell' => [
|
||||||
'label' => lng('serversettings.allow_allow_customer_shell'),
|
'label' => lng('serversettings.allow_allow_customer_shell'),
|
||||||
@@ -84,7 +89,8 @@ return [
|
|||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_available_shells' => [
|
'system_available_shells' => [
|
||||||
'label' => lng('serversettings.available_shells'),
|
'label' => lng('serversettings.available_shells'),
|
||||||
@@ -94,7 +100,8 @@ return [
|
|||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_froxlorusergroup' => [
|
'system_froxlorusergroup' => [
|
||||||
'label' => lng('serversettings.froxlorusergroup'),
|
'label' => lng('serversettings.froxlorusergroup'),
|
||||||
@@ -108,7 +115,8 @@ return [
|
|||||||
'checkLocalGroup'
|
'checkLocalGroup'
|
||||||
],
|
],
|
||||||
'visible' => Settings::Get('system.nssextrausers'),
|
'visible' => Settings::Get('system.nssextrausers'),
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -44,24 +44,30 @@ return [
|
|||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'diskquota_repquota_path',
|
'varname' => 'diskquota_repquota_path',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
'string_type' => 'file',
|
||||||
'default' => '/usr/sbin/repquota',
|
'default' => '/usr/sbin/repquota',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_diskquota_quotatool_path' => [
|
'system_diskquota_quotatool_path' => [
|
||||||
'label' => lng('serversettings.diskquota_quotatool_path.description'),
|
'label' => lng('serversettings.diskquota_quotatool_path.description'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'diskquota_quotatool_path',
|
'varname' => 'diskquota_quotatool_path',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
'string_type' => 'file',
|
||||||
'default' => '/usr/bin/quotatool',
|
'default' => '/usr/bin/quotatool',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_diskquota_customer_partition' => [
|
'system_diskquota_customer_partition' => [
|
||||||
'label' => lng('serversettings.diskquota_customer_partition.description'),
|
'label' => lng('serversettings.diskquota_customer_partition.description'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'diskquota_customer_partition',
|
'varname' => 'diskquota_customer_partition',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
'string_type' => 'file',
|
||||||
'default' => '/dev/root',
|
'default' => '/dev/root',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
87
actions/admin/settings/230.backup.php
Normal file
87
actions/admin/settings/230.backup.php
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
return [
|
||||||
|
'groups' => [
|
||||||
|
'backup' => [
|
||||||
|
'title' => lng('backup'),
|
||||||
|
'icon' => 'fa-solid fa-sliders',
|
||||||
|
'advanced_mode' => true,
|
||||||
|
'fields' => [
|
||||||
|
'backup_enabled' => [
|
||||||
|
'label' => lng('serversettings.backup_enabled'),
|
||||||
|
'settinggroup' => 'backup',
|
||||||
|
'varname' => 'enabled',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'default' => false,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'overview_option' => true,
|
||||||
|
'cronmodule' => 'froxlor/backup'
|
||||||
|
],
|
||||||
|
'backup_default_storage' => [
|
||||||
|
'label' => lng('serversettings.backup_default_storage'),
|
||||||
|
'settinggroup' => 'backup',
|
||||||
|
'varname' => 'default_storage',
|
||||||
|
'type' => 'select',
|
||||||
|
'default' => '1',
|
||||||
|
'option_options_method' => [
|
||||||
|
'\\Froxlor\\Backup\\Backup',
|
||||||
|
'getBackupStorages'
|
||||||
|
],
|
||||||
|
'save_method' => 'storeSettingField'
|
||||||
|
],
|
||||||
|
'backup_default_retention' => [
|
||||||
|
'label' => lng('serversettings.backup_default_retention'),
|
||||||
|
'settinggroup' => 'backup',
|
||||||
|
'varname' => 'default_retention',
|
||||||
|
'type' => 'number',
|
||||||
|
'default' => 3,
|
||||||
|
'min' => 0,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
],
|
||||||
|
'backup_default_customer_access' => [
|
||||||
|
'label' => lng('serversettings.backup_default_customer_access'),
|
||||||
|
'settinggroup' => 'backup',
|
||||||
|
'varname' => 'default_customer_access',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'default' => true,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
],
|
||||||
|
'backup_default_pgp_public_key' => [
|
||||||
|
'label' => lng('serversettings.backup_default_pgp_public_key'),
|
||||||
|
'settinggroup' => 'backup',
|
||||||
|
'varname' => 'default_pgp_public_key',
|
||||||
|
'type' => 'textarea',
|
||||||
|
'default' => '',
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'plausibility_check_method' => [
|
||||||
|
'\\Froxlor\\Validate\\Check',
|
||||||
|
'checkPgpPublicKeySetting'
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
@@ -77,6 +77,7 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin
|
|||||||
$result['switched_user'] = CurrentUser::getData();
|
$result['switched_user'] = CurrentUser::getData();
|
||||||
$result['adminsession'] = 1;
|
$result['adminsession'] = 1;
|
||||||
$result['userid'] = $result['adminid'];
|
$result['userid'] = $result['adminid'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
|
|
||||||
$log->logAction(
|
$log->logAction(
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ if ($action == 'delete' && function_exists('apcu_clear_cache') && $userinfo['cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!function_exists('apcu_cache_info') || !function_exists('apcu_sma_info')) {
|
if (!function_exists('apcu_cache_info') || !function_exists('apcu_sma_info')) {
|
||||||
Response::standardError(lng('error.no_apcuinfo'));
|
Response::standardError('no_apcuinfo');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
|
if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ require __DIR__ . '/lib/init.php';
|
|||||||
|
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\Http\HttpClient;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\Install\AutoUpdate;
|
use Froxlor\Install\AutoUpdate;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
@@ -132,7 +132,7 @@ elseif ($page == 'getdownload') {
|
|||||||
elseif ($page == 'extract') {
|
elseif ($page == 'extract') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
$toExtract = isset($_POST['archive']) ? $_POST['archive'] : null;
|
$toExtract = isset($_POST['archive']) ? $_POST['archive'] : null;
|
||||||
$localArchive = Froxlor::getInstallDir() . '/updates/' . $toExtract;
|
$localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract);
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Extracting " . $localArchive . " to " . Froxlor::getInstallDir());
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Extracting " . $localArchive . " to " . Froxlor::getInstallDir());
|
||||||
$result = AutoUpdate::extractZip($localArchive);
|
$result = AutoUpdate::extractZip($localArchive);
|
||||||
if ($result > 0) {
|
if ($result > 0) {
|
||||||
@@ -146,7 +146,7 @@ elseif ($page == 'extract') {
|
|||||||
Response::redirectTo('admin_updates.php');
|
Response::redirectTo('admin_updates.php');
|
||||||
} else {
|
} else {
|
||||||
$toExtract = isset($_GET['archive']) ? $_GET['archive'] : null;
|
$toExtract = isset($_GET['archive']) ? $_GET['archive'] : null;
|
||||||
$localArchive = Froxlor::getInstallDir() . '/updates/' . $toExtract;
|
$localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_exists($localArchive)) {
|
if (!file_exists($localArchive)) {
|
||||||
|
|||||||
183
admin_backups.php
Normal file
183
admin_backups.php
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
const AREA = 'admin';
|
||||||
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
|
use Froxlor\Api\Commands\Backups;
|
||||||
|
use Froxlor\Api\Commands\BackupStorages;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\UI\Collection;
|
||||||
|
use Froxlor\UI\HTML;
|
||||||
|
use Froxlor\UI\Listing;
|
||||||
|
use Froxlor\UI\Panel\UI;
|
||||||
|
use Froxlor\UI\Request;
|
||||||
|
use Froxlor\UI\Response;
|
||||||
|
|
||||||
|
$id = (int)Request::any('id');
|
||||||
|
|
||||||
|
if (($page == 'backups' || $page == 'overview')) {
|
||||||
|
if ($action == '') {
|
||||||
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "viewed admin_backups");
|
||||||
|
|
||||||
|
try {
|
||||||
|
$admin_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.backups.php';
|
||||||
|
$collection = (new Collection(Backups::class, $userinfo))
|
||||||
|
->withPagination($admin_list_data['backups_list']['columns'], $admin_list_data['backups_list']['default_sorting']);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
UI::view('user/table.html.twig', [
|
||||||
|
'listing' => Listing::format($collection, $admin_list_data, 'backups_list'),
|
||||||
|
'actions_links' => [
|
||||||
|
[
|
||||||
|
'href' => $linker->getLink(['section' => 'backups', 'page' => $page, 'action' => 'restore']),
|
||||||
|
'label' => lng('admin.backups_restore'),
|
||||||
|
'icon' => 'fa-solid fa-file-import',
|
||||||
|
'class' => 'btn-outline-secondary'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'href' => $linker->getLink(['section' => 'backups', 'page' => 'storages']),
|
||||||
|
'label' => lng('admin.backup_storages'),
|
||||||
|
'icon' => 'fa-solid fa-hard-drive',
|
||||||
|
'class' => 'btn-outline-secondary',
|
||||||
|
'visible' => $userinfo['change_serversettings'] == '1'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} elseif ($action == 'delete' && $id != 0) {
|
||||||
|
|
||||||
|
} elseif ($action == 'add') {
|
||||||
|
|
||||||
|
} elseif ($action == 'edit' && $id != 0) {
|
||||||
|
|
||||||
|
} elseif ($action == 'restore') {
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if ($page == 'storages' && $userinfo['change_serversettings'] == '1') {
|
||||||
|
if ($action == '') {
|
||||||
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "list backup storages");
|
||||||
|
|
||||||
|
try {
|
||||||
|
$backup_storage_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.backup_storages.php';
|
||||||
|
$collection = (new Collection(BackupStorages::class, $userinfo))
|
||||||
|
->withPagination($backup_storage_list_data['backup_storages_list']['columns'], $backup_storage_list_data['backup_storages_list']['default_sorting']);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
UI::view('user/table.html.twig', [
|
||||||
|
'listing' => Listing::format($collection, $backup_storage_list_data, 'backup_storages_list'),
|
||||||
|
'actions_links' => [
|
||||||
|
[
|
||||||
|
'href' => $linker->getLink(['section' => 'backups', 'page' => 'backups']),
|
||||||
|
'label' => lng('admin.backups'),
|
||||||
|
'icon' => 'fa-solid fa-reply'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'href' => $linker->getLink(['section' => 'backups', 'page' => $page, 'action' => 'add']),
|
||||||
|
'label' => lng('admin.backup_storage_add')
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} elseif ($action == 'delete' && $id != 0) {
|
||||||
|
try {
|
||||||
|
$json_result = BackupStorages::getLocal($userinfo, [
|
||||||
|
'id' => $id
|
||||||
|
])->get();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
$result = json_decode($json_result, true)['data'];
|
||||||
|
|
||||||
|
if ($result['id'] != '') {
|
||||||
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
|
BackupStorages::getLocal($userinfo, [
|
||||||
|
'id' => $id
|
||||||
|
])->delete();
|
||||||
|
Response::redirectTo($filename, [
|
||||||
|
'page' => $page
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
HTML::askYesNo('backup_backup_server_reallydelete', $filename, [
|
||||||
|
'id' => $id,
|
||||||
|
'page' => $page,
|
||||||
|
'action' => $action
|
||||||
|
], $result['id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif ($action == 'add') {
|
||||||
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
|
try {
|
||||||
|
BackupStorages::getLocal($userinfo, $_POST)->add();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
Response::redirectTo($filename, [
|
||||||
|
'page' => $page
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$admin_add_data = include_once dirname(__FILE__) . '/lib/formfields/admin/backup_storages/formfield.backup_storage_add.php';
|
||||||
|
|
||||||
|
UI::view('user/form.html.twig', [
|
||||||
|
'formaction' => $linker->getLink(['section' => 'backups']),
|
||||||
|
'formdata' => $admin_add_data['backup_storage_add']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} elseif ($action == 'edit' && $id != 0) {
|
||||||
|
try {
|
||||||
|
$json_result = BackupStorages::getLocal($userinfo, [
|
||||||
|
'id' => $id
|
||||||
|
])->get();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
$result = json_decode($json_result, true)['data'];
|
||||||
|
|
||||||
|
if ($result['id'] != '') {
|
||||||
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
|
try {
|
||||||
|
BackupStorages::getLocal($userinfo, $_POST)->update();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
Response::redirectTo($filename, [
|
||||||
|
'page' => $page
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$backup_storage_edit_data = include_once dirname(__FILE__) . '/lib/formfields/admin/backup_storages/formfield.backup_storage_edit.php';
|
||||||
|
|
||||||
|
UI::view('user/form.html.twig', [
|
||||||
|
'formaction' => $linker->getLink(['section' => 'backups', 'id' => $id]),
|
||||||
|
'formdata' => $backup_storage_edit_data['backup_storage_edit'],
|
||||||
|
'editid' => $id
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Response::dynamicError('403');
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ use Froxlor\Settings;
|
|||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
|
|
||||||
if ($userinfo['change_serversettings'] == '1') {
|
if ($userinfo['change_serversettings'] == '1') {
|
||||||
if ($action == 'setconfigured') {
|
if ($action == 'setconfigured') {
|
||||||
@@ -91,6 +92,7 @@ if ($userinfo['change_serversettings'] == '1') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($distribution != "" && isset($_POST['finish'])) {
|
if ($distribution != "" && isset($_POST['finish'])) {
|
||||||
|
$valid_keys = ['http', 'dns', 'smtp', 'mail', 'ftp', 'system', 'distro'];
|
||||||
unset($_POST['finish']);
|
unset($_POST['finish']);
|
||||||
unset($_POST['csrf_token']);
|
unset($_POST['csrf_token']);
|
||||||
$params = $_POST;
|
$params = $_POST;
|
||||||
@@ -99,6 +101,20 @@ if ($userinfo['change_serversettings'] == '1') {
|
|||||||
foreach ($_POST['system'] as $sysdaemon) {
|
foreach ($_POST['system'] as $sysdaemon) {
|
||||||
$params['system'][] = $sysdaemon;
|
$params['system'][] = $sysdaemon;
|
||||||
}
|
}
|
||||||
|
// validate params
|
||||||
|
foreach ($params as $key => $value) {
|
||||||
|
if (!in_array($key, $valid_keys)) {
|
||||||
|
unset($params[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!is_array($value)) {
|
||||||
|
$params[$key] = Validate::validate($value, $key);
|
||||||
|
} else {
|
||||||
|
foreach ($value as $subkey => $subvalue) {
|
||||||
|
$params[$key][$subkey] = Validate::validate($subvalue, $key.'.'.$subkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
$params_content = json_encode($params);
|
$params_content = json_encode($params);
|
||||||
$params_filename = FileDir::makeCorrectFile(Froxlor::getInstallDir() . 'install/' . Froxlor::genSessionId() . '.json');
|
$params_filename = FileDir::makeCorrectFile(Froxlor::getInstallDir() . 'install/' . Froxlor::genSessionId() . '.json');
|
||||||
file_put_contents($params_filename, $params_content);
|
file_put_contents($params_filename, $params_content);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const AREA = 'admin';
|
|||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\Api\Commands\Admins;
|
use Froxlor\Api\Commands\Admins;
|
||||||
|
use Froxlor\Api\Commands\BackupStorages;
|
||||||
use Froxlor\Api\Commands\Customers;
|
use Froxlor\Api\Commands\Customers;
|
||||||
use Froxlor\Api\Commands\MysqlServer;
|
use Froxlor\Api\Commands\MysqlServer;
|
||||||
use Froxlor\CurrentUser;
|
use Froxlor\CurrentUser;
|
||||||
@@ -93,6 +94,7 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
|
|||||||
$result['switched_user'] = CurrentUser::getData();
|
$result['switched_user'] = CurrentUser::getData();
|
||||||
$result['adminsession'] = 0;
|
$result['adminsession'] = 0;
|
||||||
$result['userid'] = $result['customerid'];
|
$result['userid'] = $result['customerid'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
|
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "switched user and is now '" . $destination_user . "'");
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "switched user and is now '" . $destination_user . "'");
|
||||||
@@ -224,6 +226,23 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
|
|||||||
$hosting_plans[$row['id']] = $row['name'];
|
$hosting_plans[$row['id']] = $row['name'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// backup storages
|
||||||
|
$backup_storages = [];
|
||||||
|
if (Settings::Get('backup.enabled') == '1' && $userinfo['change_serversettings'] == '1') {
|
||||||
|
$backup_storages = [
|
||||||
|
0 => lng('backup.storage_none')
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
$result_json = BackupStorages::getLocal($userinfo)->listing();
|
||||||
|
$result_decoded = json_decode($result_json, true)['data']['list'];
|
||||||
|
foreach ($result_decoded as $storagedata) {
|
||||||
|
$backup_storages[$storagedata['id']] = "[" . $storagedata['type'] . "] " . html_entity_decode($storagedata['description']);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
/* just none */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$customer_add_data = include_once dirname(__FILE__) . '/lib/formfields/admin/customer/formfield.customer_add.php';
|
$customer_add_data = include_once dirname(__FILE__) . '/lib/formfields/admin/customer/formfield.customer_add.php';
|
||||||
|
|
||||||
UI::view('user/form.html.twig', [
|
UI::view('user/form.html.twig', [
|
||||||
@@ -306,6 +325,23 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
|
|||||||
$hosting_plans[$row['id']] = $row['name'];
|
$hosting_plans[$row['id']] = $row['name'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// backup storages
|
||||||
|
$backup_storages = [];
|
||||||
|
if (Settings::Get('backup.enabled') == '1' && $userinfo['change_serversettings'] == '1') {
|
||||||
|
$backup_storages = [
|
||||||
|
0 => lng('backup.storage_none')
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
$result_json = BackupStorages::getLocal($userinfo)->listing();
|
||||||
|
$result_decoded = json_decode($result_json, true)['data']['list'];
|
||||||
|
foreach ($result_decoded as $storagedata) {
|
||||||
|
$backup_storages[$storagedata['id']] = "[" . $storagedata['type'] . "] " . html_entity_decode($storagedata['description']);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
/* just none */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$available_admins_stmt = Database::prepare("
|
$available_admins_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_ADMINS . "`
|
SELECT * FROM `" . TABLE_PANEL_ADMINS . "`
|
||||||
WHERE (`customers` = '-1' OR `customers` > `customers_used`)
|
WHERE (`customers` = '-1' OR `customers` > `customers_used`)
|
||||||
|
|||||||
@@ -114,15 +114,11 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
} elseif ($alias_check['count'] > 0) {
|
} elseif ($alias_check['count'] > 0) {
|
||||||
Response::standardError('domains_cantdeletedomainwithaliases');
|
Response::standardError('domains_cantdeletedomainwithaliases');
|
||||||
} else {
|
} else {
|
||||||
$showcheck = false;
|
HTML::askYesNo('admin_domain_reallydelete', $filename, [
|
||||||
if (Domain::domainHasMainSubDomains($id)) {
|
|
||||||
$showcheck = true;
|
|
||||||
}
|
|
||||||
HTML::askYesNoWithCheckbox('admin_domain_reallydelete', 'remove_subbutmain_domains', $filename, [
|
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'action' => $action
|
'action' => $action
|
||||||
], $idna_convert->decode($result['domain']), $showcheck);
|
], $idna_convert->decode($result['domain']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($action == 'add') {
|
} elseif ($action == 'add') {
|
||||||
@@ -252,21 +248,6 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
$domains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']) . ' (' . $row_domain['loginname'] . ')';
|
$domains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']) . ' (' . $row_domain['loginname'] . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
$subtodomains = [
|
|
||||||
0 => lng('domains.nosubtomaindomain')
|
|
||||||
];
|
|
||||||
$result_domains_stmt = Database::prepare("
|
|
||||||
SELECT `d`.`id`, `d`.`domain`, `c`.`loginname` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c`
|
|
||||||
WHERE `d`.`aliasdomain` IS NULL AND `d`.`parentdomainid` = 0 AND `d`.`ismainbutsubto` = 0 " . $standardsubdomains . ($userinfo['customers_see_all'] ? '' : " AND `d`.`adminid` = :adminid") . "
|
|
||||||
AND `d`.`customerid`=`c`.`customerid` ORDER BY `loginname`, `domain` ASC
|
|
||||||
");
|
|
||||||
// params from above still valid
|
|
||||||
Database::pexecute($result_domains_stmt, $params);
|
|
||||||
|
|
||||||
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
||||||
$subtodomains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']) . ' (' . $row_domain['loginname'] . ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
$phpconfigs = [];
|
$phpconfigs = [];
|
||||||
$configs = Database::query("
|
$configs = Database::query("
|
||||||
SELECT c.*, fc.description as interpreter
|
SELECT c.*, fc.description as interpreter
|
||||||
@@ -282,6 +263,12 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$openbasedir = [
|
||||||
|
0 => lng('domain.docroot'),
|
||||||
|
1 => lng('domain.homedir'),
|
||||||
|
2 => lng('domain.docparent')
|
||||||
|
];
|
||||||
|
|
||||||
// create serveralias options
|
// create serveralias options
|
||||||
$serveraliasoptions = [
|
$serveraliasoptions = [
|
||||||
0 => lng('domains.serveraliasoption_wildcard'),
|
0 => lng('domains.serveraliasoption_wildcard'),
|
||||||
@@ -463,27 +450,6 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
$domains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']);
|
$domains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$subtodomains = [
|
|
||||||
0 => lng('domains.nosubtomaindomain')
|
|
||||||
];
|
|
||||||
$result_domains_stmt = Database::prepare("
|
|
||||||
SELECT `d`.`id`, `d`.`domain` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c`
|
|
||||||
WHERE `d`.`aliasdomain` IS NULL AND `d`.`parentdomainid` = '0' AND `d`.`id` <> :id
|
|
||||||
AND `c`.`standardsubdomain`<>`d`.`id` AND `c`.`customerid`=`d`.`customerid`" . ($userinfo['customers_see_all'] ? '' : " AND `d`.`adminid` = :adminid") . "
|
|
||||||
ORDER BY `d`.`domain` ASC
|
|
||||||
");
|
|
||||||
$params = [
|
|
||||||
'id' => $result['id']
|
|
||||||
];
|
|
||||||
if ($userinfo['customers_see_all'] == '0') {
|
|
||||||
$params['adminid'] = $userinfo['adminid'];
|
|
||||||
}
|
|
||||||
Database::pexecute($result_domains_stmt, $params);
|
|
||||||
|
|
||||||
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
||||||
$subtodomains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($userinfo['ip'] == "-1") {
|
if ($userinfo['ip'] == "-1") {
|
||||||
$result_ipsandports_stmt = Database::query("
|
$result_ipsandports_stmt = Database::query("
|
||||||
SELECT `id`, `ip`, `port` FROM `" . TABLE_PANEL_IPSANDPORTS . "` WHERE `ssl`='0' ORDER BY `ip`, `port` ASC
|
SELECT `id`, `ip`, `port` FROM `" . TABLE_PANEL_IPSANDPORTS . "` WHERE `ssl`='0' ORDER BY `ip`, `port` ASC
|
||||||
@@ -545,6 +511,12 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
$result['temporary_ssl_redirect'] = $result['ssl_redirect'];
|
$result['temporary_ssl_redirect'] = $result['ssl_redirect'];
|
||||||
$result['ssl_redirect'] = ($result['ssl_redirect'] == 0 ? 0 : 1);
|
$result['ssl_redirect'] = ($result['ssl_redirect'] == 0 ? 0 : 1);
|
||||||
|
|
||||||
|
$openbasedir = [
|
||||||
|
0 => lng('domain.docroot'),
|
||||||
|
1 => lng('domain.homedir'),
|
||||||
|
2 => lng('domain.docparent')
|
||||||
|
];
|
||||||
|
|
||||||
$serveraliasoptions = [
|
$serveraliasoptions = [
|
||||||
0 => lng('domains.serveraliasoption_wildcard'),
|
0 => lng('domains.serveraliasoption_wildcard'),
|
||||||
1 => lng('domains.serveraliasoption_www'),
|
1 => lng('domains.serveraliasoption_www'),
|
||||||
@@ -664,6 +636,23 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
'alert_msg' => lng('domains.import_description')
|
'alert_msg' => lng('domains.import_description')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
} elseif ($action == 'duplicate') {
|
||||||
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
|
try {
|
||||||
|
Domains::getLocal($userinfo, $_POST)->duplicate();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
Response::redirectTo($filename, [
|
||||||
|
'page' => $page,
|
||||||
|
'searchfield' => 'd.domain_ace',
|
||||||
|
'searchtext' => $_POST['domain'] ?? ""
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
Response::redirectTo($filename, [
|
||||||
|
'page' => 'overview'
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} elseif ($page == 'domainssleditor') {
|
} elseif ($page == 'domainssleditor') {
|
||||||
require_once __DIR__ . '/ssl_editor.php';
|
require_once __DIR__ . '/ssl_editor.php';
|
||||||
|
|||||||
168
admin_index.php
168
admin_index.php
@@ -31,6 +31,7 @@ use Froxlor\Api\Commands\Froxlor as Froxlor;
|
|||||||
use Froxlor\CurrentUser;
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\Language;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\Crypt;
|
use Froxlor\System\Crypt;
|
||||||
@@ -38,7 +39,6 @@ use Froxlor\UI\Panel\UI;
|
|||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use Froxlor\Language;
|
|
||||||
|
|
||||||
$id = (int)Request::any('id');
|
$id = (int)Request::any('id');
|
||||||
|
|
||||||
@@ -53,6 +53,7 @@ if ($action == 'logout') {
|
|||||||
if (is_array(CurrentUser::getField('switched_user'))) {
|
if (is_array(CurrentUser::getField('switched_user'))) {
|
||||||
$result = CurrentUser::getData();
|
$result = CurrentUser::getData();
|
||||||
$result = $result['switched_user'];
|
$result = $result['switched_user'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
||||||
$redirect = "admin_" . $target . ".php";
|
$redirect = "admin_" . $target . ".php";
|
||||||
@@ -196,107 +197,104 @@ if ($page == 'overview') {
|
|||||||
'outstanding_tasks' => $outstanding_tasks,
|
'outstanding_tasks' => $outstanding_tasks,
|
||||||
'cron_last_runs' => $cron_last_runs
|
'cron_last_runs' => $cron_last_runs
|
||||||
]);
|
]);
|
||||||
} elseif ($page == 'change_password') {
|
} elseif ($page == 'profile') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
$languages = Language::getLanguages();
|
||||||
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
|
||||||
|
|
||||||
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_ADMINS, 'adminid')) {
|
if (!empty($_POST)) {
|
||||||
Response::standardError('oldpasswordnotcorrect');
|
if ($_POST['send'] == 'changepassword') {
|
||||||
}
|
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
||||||
|
|
||||||
try {
|
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_ADMINS, 'adminid')) {
|
||||||
$new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
|
Response::standardError('oldpasswordnotcorrect');
|
||||||
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
|
}
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($old_password == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.old_password'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.new_password'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password_confirm == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.new_password_confirm'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password != $new_password_confirm) {
|
|
||||||
Response::standardError('newpasswordconfirmerror');
|
|
||||||
} else {
|
|
||||||
try {
|
try {
|
||||||
Admins::getLocal($userinfo, [
|
$new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
|
||||||
'id' => $userinfo['adminid'],
|
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
|
||||||
'admin_password' => $new_password
|
|
||||||
])->update();
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'changed password');
|
|
||||||
|
if ($old_password == '') {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'changepassword.old_password'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password == '') {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'changepassword.new_password'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password_confirm == '') {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'changepassword.new_password_confirm'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password != $new_password_confirm) {
|
||||||
|
Response::standardError('newpasswordconfirmerror');
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Admins::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['adminid'],
|
||||||
|
'admin_password' => $new_password
|
||||||
|
])->update();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'changed password');
|
||||||
|
Response::redirectTo($filename);
|
||||||
|
}
|
||||||
|
} elseif ($_POST['send'] == 'changetheme') {
|
||||||
|
if (Settings::Get('panel.allow_theme_change_admin') == 1) {
|
||||||
|
$theme = Validate::validate($_POST['theme'], 'theme');
|
||||||
|
try {
|
||||||
|
Admins::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['adminid'],
|
||||||
|
'theme' => $theme
|
||||||
|
])->update();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her theme to '" . $theme . "'");
|
||||||
|
}
|
||||||
|
Response::redirectTo($filename);
|
||||||
|
} elseif ($_POST['send'] == 'changelanguage') {
|
||||||
|
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
||||||
|
|
||||||
|
if (isset($languages[$def_language])) {
|
||||||
|
try {
|
||||||
|
Admins::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['adminid'],
|
||||||
|
'def_language' => $def_language
|
||||||
|
])->update();
|
||||||
|
CurrentUser::setField('language', $def_language);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her default language to '" . $def_language . "'");
|
||||||
Response::redirectTo($filename);
|
Response::redirectTo($filename);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UI::view('user/change_password.html.twig');
|
// change theme
|
||||||
}
|
$default_theme = Settings::Get('panel.default_theme');
|
||||||
} elseif ($page == 'change_language') {
|
if ($userinfo['theme'] != '') {
|
||||||
$languages = Language::getLanguages();
|
$default_theme = $userinfo['theme'];
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
|
||||||
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
|
||||||
|
|
||||||
if (isset($languages[$def_language])) {
|
|
||||||
try {
|
|
||||||
Admins::getLocal($userinfo, [
|
|
||||||
'id' => $userinfo['adminid'],
|
|
||||||
'def_language' => $def_language
|
|
||||||
])->update();
|
|
||||||
CurrentUser::setField('language', $def_language);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her default language to '" . $def_language . "'");
|
$themes_avail = UI::getThemes();
|
||||||
Response::redirectTo($filename);
|
|
||||||
} else {
|
// change language
|
||||||
$default_lang = Settings::Get('panel.standardlanguage');
|
$default_lang = Settings::Get('panel.standardlanguage');
|
||||||
if ($userinfo['def_language'] != '') {
|
if ($userinfo['def_language'] != '') {
|
||||||
$default_lang = $userinfo['def_language'];
|
$default_lang = $userinfo['def_language'];
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('user/change_language.html.twig', [
|
UI::view('user/profile.html.twig', [
|
||||||
'languages' => $languages,
|
|
||||||
'default_lang' => $default_lang
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} elseif ($page == 'change_theme') {
|
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
|
||||||
$theme = Validate::validate($_POST['theme'], 'theme');
|
|
||||||
try {
|
|
||||||
Admins::getLocal($userinfo, [
|
|
||||||
'id' => $userinfo['adminid'],
|
|
||||||
'theme' => $theme
|
|
||||||
])->update();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her theme to '" . $theme . "'");
|
|
||||||
Response::redirectTo($filename);
|
|
||||||
} else {
|
|
||||||
$default_theme = Settings::Get('panel.default_theme');
|
|
||||||
if ($userinfo['theme'] != '') {
|
|
||||||
$default_theme = $userinfo['theme'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$themes_avail = UI::getThemes();
|
|
||||||
|
|
||||||
UI::view('user/change_theme.html.twig', [
|
|
||||||
'themes' => $themes_avail,
|
'themes' => $themes_avail,
|
||||||
'default_theme' => $default_theme
|
'default_theme' => $default_theme,
|
||||||
|
'languages' => $languages,
|
||||||
|
'default_lang' => $default_lang,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} elseif ($page == 'send_error_report' && Settings::Get('system.allow_error_report_admin') == '1') {
|
} elseif ($page == 'send_error_report' && Settings::Get('system.allow_error_report_admin') == '1') {
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ const AREA = 'admin';
|
|||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\UI\HTML;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\UI\HTML;
|
|
||||||
|
|
||||||
if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_serversettings'] == '1') {
|
if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_serversettings'] == '1') {
|
||||||
if ($_POST['send'] == 'send') {
|
if ($_POST['send'] == 'send') {
|
||||||
@@ -57,252 +57,30 @@ if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!function_exists('opcache_get_configuration')) {
|
if (!extension_loaded('Zend OPcache')) {
|
||||||
Response::standardError(lng('error.no_opcacheinfo'));
|
Response::standardError('no_opcacheinfo');
|
||||||
|
}
|
||||||
|
|
||||||
|
$ocEnabled = ini_get('opcache.enable');
|
||||||
|
if (empty($ocEnabled)) {
|
||||||
|
Response::standardError('inactive_opcacheinfo');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
|
if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
|
||||||
$time = time();
|
$time = time();
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed OPcache info");
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed OPcache info");
|
||||||
|
|
||||||
$optimizationLevels = [
|
$opcache = (new \Amnuts\Opcache\Service())->getData();
|
||||||
1 << 0 => 'CSE, STRING construction',
|
|
||||||
1 << 1 => 'Constant conversion and jumps',
|
|
||||||
1 << 2 => '++, +=, series of jumps',
|
|
||||||
1 << 3 => 'INIT_FCALL_BY_NAME -> DO_FCALL',
|
|
||||||
1 << 4 => 'CFG based optimization',
|
|
||||||
1 << 5 => 'DFA based optimization',
|
|
||||||
1 << 6 => 'CALL GRAPH optimization',
|
|
||||||
1 << 7 => 'SCCP (constant propagation)',
|
|
||||||
1 << 8 => 'TMP VAR usage',
|
|
||||||
1 << 9 => 'NOP removal',
|
|
||||||
1 << 10 => 'Merge equal constants',
|
|
||||||
1 << 11 => 'Adjust used stack',
|
|
||||||
1 << 12 => 'Remove unused variables',
|
|
||||||
1 << 13 => 'DCE (dead code elimination)',
|
|
||||||
1 << 14 => '(unsafe) Collect constants',
|
|
||||||
1 << 15 => 'Inline functions'
|
|
||||||
];
|
|
||||||
|
|
||||||
$jitModes = [
|
|
||||||
[
|
|
||||||
'flag' => 'CPU-specific optimization',
|
|
||||||
'value' => [
|
|
||||||
'Disable CPU-specific optimization',
|
|
||||||
'Enable use of AVX, if the CPU supports it'
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'flag' => 'Register allocation',
|
|
||||||
'value' => [
|
|
||||||
'Do not perform register allocation',
|
|
||||||
'Perform block-local register allocation',
|
|
||||||
'Perform global register allocation'
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'flag' => 'Trigger',
|
|
||||||
'value' => [
|
|
||||||
'Compile all functions on script load',
|
|
||||||
'Compile functions on first execution',
|
|
||||||
'Profile functions on first request and compile the hottest functions afterwards',
|
|
||||||
'Profile on the fly and compile hot functions',
|
|
||||||
'Currently unused',
|
|
||||||
'Use tracing JIT. Profile on the fly and compile traces for hot code segments'
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'flag' => 'Optimization level',
|
|
||||||
'value' => [
|
|
||||||
'No JIT',
|
|
||||||
'Minimal JIT (call standard VM handlers)',
|
|
||||||
'Inline VM handlers',
|
|
||||||
'Use type inference',
|
|
||||||
'Use call graph',
|
|
||||||
'Optimize whole script'
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
$jitModeMapping = [
|
|
||||||
'tracing' => 1254,
|
|
||||||
'on' => 1254,
|
|
||||||
'function' => 1205
|
|
||||||
];
|
|
||||||
|
|
||||||
$status = opcache_get_status(false);
|
|
||||||
$config = opcache_get_configuration();
|
|
||||||
$missingConfig = array_diff_key(ini_get_all('zend opcache', false), $config['directives']);
|
|
||||||
if (!empty($missingConfig)) {
|
|
||||||
$config['directives'] = array_merge($config['directives'], $missingConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = [];
|
|
||||||
if (!empty($status['scripts'])) {
|
|
||||||
uasort($status['scripts'], static function ($a, $b) {
|
|
||||||
return $a['hits'] <=> $b['hits'];
|
|
||||||
});
|
|
||||||
foreach ($status['scripts'] as &$file) {
|
|
||||||
$file['full_path'] = str_replace('\\', '/', $file['full_path']);
|
|
||||||
$file['readable'] = [
|
|
||||||
'hits' => number_format($file['hits']),
|
|
||||||
'memory_consumption' => bsize($file['memory_consumption'])
|
|
||||||
];
|
|
||||||
}
|
|
||||||
$files = array_values($status['scripts']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($config['directives']['opcache.file_cache_only'] || !empty($status['file_cache_only'])) {
|
|
||||||
$overview = false;
|
|
||||||
} else {
|
|
||||||
$status['opcache_statistics']['start_time'] = $status['opcache_statistics']['start_time'] ?? time();
|
|
||||||
$status['opcache_statistics']['last_restart_time'] = $status['opcache_statistics']['last_restart_time'] ?? time();
|
|
||||||
|
|
||||||
$overview = array_merge(
|
|
||||||
$status['memory_usage'],
|
|
||||||
$status['opcache_statistics'],
|
|
||||||
[
|
|
||||||
'total_memory' => $config['directives']['opcache.memory_consumption'],
|
|
||||||
'used_memory_percentage' => round(100 * (
|
|
||||||
($status['memory_usage']['used_memory'] + $status['memory_usage']['wasted_memory'])
|
|
||||||
/ $config['directives']['opcache.memory_consumption']
|
|
||||||
)),
|
|
||||||
'hit_rate_percentage' => round($status['opcache_statistics']['opcache_hit_rate']),
|
|
||||||
'used_key_percentage' => round(100 * ($status['opcache_statistics']['num_cached_keys']
|
|
||||||
/ $status['opcache_statistics']['max_cached_keys']
|
|
||||||
)),
|
|
||||||
'wasted_percentage' => round($status['memory_usage']['current_wasted_percentage'], 2),
|
|
||||||
'readable' => [
|
|
||||||
'total_memory' => bsize($config['directives']['opcache.memory_consumption']),
|
|
||||||
'used_memory' => bsize($status['memory_usage']['used_memory']),
|
|
||||||
'free_memory' => bsize($status['memory_usage']['free_memory']),
|
|
||||||
'wasted_memory' => bsize($status['memory_usage']['wasted_memory']),
|
|
||||||
'num_cached_scripts' => number_format($status['opcache_statistics']['num_cached_scripts']),
|
|
||||||
'hits' => number_format($status['opcache_statistics']['hits']),
|
|
||||||
'misses' => number_format($status['opcache_statistics']['misses']),
|
|
||||||
'blacklist_miss' => number_format($status['opcache_statistics']['blacklist_misses']),
|
|
||||||
'num_cached_keys' => number_format($status['opcache_statistics']['num_cached_keys']),
|
|
||||||
'max_cached_keys' => number_format($status['opcache_statistics']['max_cached_keys']),
|
|
||||||
'interned' => null,
|
|
||||||
'start_time' => (new DateTimeImmutable("@{$status['opcache_statistics']['start_time']}"))
|
|
||||||
->setTimezone(new DateTimeZone(date_default_timezone_get()))
|
|
||||||
->format('Y-m-d H:i:s'),
|
|
||||||
'last_restart_time' => ($status['opcache_statistics']['last_restart_time'] == 0
|
|
||||||
? 'never'
|
|
||||||
: (new DateTimeImmutable("@{$status['opcache_statistics']['last_restart_time']}"))
|
|
||||||
->setTimezone(new DateTimeZone(date_default_timezone_get()))
|
|
||||||
->format('Y-m-d H:i:s')
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$preload = [];
|
|
||||||
if (!empty($status['preload_statistics']['scripts'])) {
|
|
||||||
$preload = $status['preload_statistics']['scripts'];
|
|
||||||
sort($preload, SORT_STRING);
|
|
||||||
if ($overview) {
|
|
||||||
$overview['preload_memory'] = $status['preload_statistics']['memory_consumption'];
|
|
||||||
$overview['readable']['preload_memory'] = bsize($status['preload_statistics']['memory_consumption']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($status['interned_strings_usage'])) {
|
|
||||||
$overview['readable']['interned'] = [
|
|
||||||
'buffer_size' => bsize($status['interned_strings_usage']['buffer_size']),
|
|
||||||
'strings_used_memory' => bsize($status['interned_strings_usage']['used_memory']),
|
|
||||||
'strings_free_memory' => bsize($status['interned_strings_usage']['free_memory']),
|
|
||||||
'number_of_strings' => number_format($status['interned_strings_usage']['number_of_strings'])
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($overview && !empty($status['jit'])) {
|
|
||||||
$overview['jit_buffer_used_percentage'] = ($status['jit']['buffer_size']
|
|
||||||
? round(100 * (($status['jit']['buffer_size'] - $status['jit']['buffer_free']) / $status['jit']['buffer_size']))
|
|
||||||
: 0
|
|
||||||
);
|
|
||||||
$overview['readable'] = array_merge($overview['readable'], [
|
|
||||||
'jit_buffer_size' => bsize($status['jit']['buffer_size']),
|
|
||||||
'jit_buffer_free' => bsize($status['jit']['buffer_free'])
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$directives = [];
|
|
||||||
ksort($config['directives']);
|
|
||||||
foreach ($config['directives'] as $k => $v) {
|
|
||||||
if (in_array($k, ['opcache.max_file_size', 'opcache.memory_consumption', 'opcache.jit_buffer_size']) && $v) {
|
|
||||||
$v = bsize($v) . " ({$v})";
|
|
||||||
} elseif ($k === 'opcache.optimization_level') {
|
|
||||||
$levels = [];
|
|
||||||
foreach ($optimizationLevels as $level => $info) {
|
|
||||||
if ($level & $v) {
|
|
||||||
$levels[] = "{$info} [{$level}]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$v = $levels ?: 'none';
|
|
||||||
} elseif ($k === 'opcache.jit') {
|
|
||||||
if ($v === '1') {
|
|
||||||
$v = 'on';
|
|
||||||
}
|
|
||||||
if (isset($jitModeMapping[$v]) || is_numeric($v)) {
|
|
||||||
$levels = [];
|
|
||||||
foreach (str_split((string)($jitModeMapping[$v] ?? $v)) as $type => $level) {
|
|
||||||
$levels[] = "{$level}: {$jitModes[$type]['value'][$level]} ({$jitModes[$type]['flag']})";
|
|
||||||
}
|
|
||||||
$v = [$v, $levels];
|
|
||||||
} elseif (empty($v) || strtolower($v) === 'off') {
|
|
||||||
$v = 'Off';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$directives[] = [
|
|
||||||
'k' => $k,
|
|
||||||
'v' => $v
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$version = array_merge(
|
|
||||||
$config['version'],
|
|
||||||
[
|
|
||||||
'php' => phpversion(),
|
|
||||||
'server' => $_SERVER['SERVER_SOFTWARE'] ?: '',
|
|
||||||
'host' => (function_exists('gethostname')
|
|
||||||
? gethostname()
|
|
||||||
: (php_uname('n')
|
|
||||||
?: (empty($_SERVER['SERVER_NAME'])
|
|
||||||
? $_SERVER['HOST_NAME']
|
|
||||||
: $_SERVER['SERVER_NAME']
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
UI::view('settings/opcacheinfo.html.twig', [
|
UI::view('settings/opcacheinfo.html.twig', [
|
||||||
'opcacheinfo' => [
|
'opcacheinfo' => [
|
||||||
'version' => $version,
|
'version' => $opcache['version'],
|
||||||
'overview' => $overview,
|
'overview' => $opcache['overview'],
|
||||||
'files' => $files,
|
'files' => $opcache['files'],
|
||||||
'preload' => $preload,
|
'preload' => $opcache['preload'],
|
||||||
'directives' => $directives,
|
'directives' => $opcache['directives'],
|
||||||
'blacklist' => $config['blacklist'],
|
'blacklist' => $opcache['blacklist'],
|
||||||
'functions' => get_extension_funcs('Zend OPcache')
|
'functions' => $opcache['functions'],
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function bsize($size)
|
|
||||||
{
|
|
||||||
$i = 0;
|
|
||||||
$val = ['b', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
||||||
while (($size / 1024) > 1) {
|
|
||||||
$size /= 1024;
|
|
||||||
++$i;
|
|
||||||
}
|
|
||||||
return sprintf(
|
|
||||||
'%.2f%s%s',
|
|
||||||
$size,
|
|
||||||
'',
|
|
||||||
$val[$i]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -70,14 +70,15 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
|
|||||||
|
|
||||||
// check if the session timeout is too low #815
|
// check if the session timeout is too low #815
|
||||||
if (isset($_POST['session_sessiontimeout']) && $_POST['session_sessiontimeout'] < 60) {
|
if (isset($_POST['session_sessiontimeout']) && $_POST['session_sessiontimeout'] < 60) {
|
||||||
Response::standardError(lng('error.session_timeout'), lng('error.session_timeout_desc'));
|
Response::standardError(['session_timeout', 'session_timeout_desc']);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (Form::processForm($settings_data, $_POST, [
|
if (Form::processForm($settings_data, $_POST, [
|
||||||
'filename' => $filename,
|
'filename' => $filename,
|
||||||
'action' => $action,
|
'action' => $action,
|
||||||
'page' => $page
|
'page' => $page,
|
||||||
|
'part' => $_part,
|
||||||
], $_part, $settings_all, $settings_part, $only_enabledisable)) {
|
], $_part, $settings_all, $settings_part, $only_enabledisable)) {
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "rebuild configfiles due to changed setting");
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "rebuild configfiles due to changed setting");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
@@ -132,7 +133,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Response::standardError(lng('error.no_phpinfo'));
|
Response::standardError('error.no_phpinfo');
|
||||||
}
|
}
|
||||||
UI::view('settings/phpinfo.html.twig', [
|
UI::view('settings/phpinfo.html.twig', [
|
||||||
'phpversion' => PHP_VERSION,
|
'phpversion' => PHP_VERSION,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Froxlor\Cli\ConfigDiff;
|
||||||
use Symfony\Component\Console\Application;
|
use Symfony\Component\Console\Application;
|
||||||
use Froxlor\Cli\RunApiCommand;
|
use Froxlor\Cli\RunApiCommand;
|
||||||
use Froxlor\Cli\ConfigServices;
|
use Froxlor\Cli\ConfigServices;
|
||||||
@@ -61,4 +62,5 @@ $application->add(new InstallCommand());
|
|||||||
$application->add(new MasterCron());
|
$application->add(new MasterCron());
|
||||||
$application->add(new UserCommand());
|
$application->add(new UserCommand());
|
||||||
$application->add(new ValidateAcmeWebroot());
|
$application->add(new ValidateAcmeWebroot());
|
||||||
|
$application->add(new ConfigDiff());
|
||||||
$application->run();
|
$application->run();
|
||||||
|
|||||||
@@ -45,6 +45,8 @@
|
|||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"ext-fileinfo": "*",
|
"ext-fileinfo": "*",
|
||||||
"ext-gmp": "*",
|
"ext-gmp": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-ftp": "*",
|
||||||
"phpmailer/phpmailer": "~6.0",
|
"phpmailer/phpmailer": "~6.0",
|
||||||
"monolog/monolog": "^1.24",
|
"monolog/monolog": "^1.24",
|
||||||
"robthree/twofactorauth": "^1.6",
|
"robthree/twofactorauth": "^1.6",
|
||||||
@@ -53,7 +55,8 @@
|
|||||||
"twig/twig": "^3.3",
|
"twig/twig": "^3.3",
|
||||||
"erusev/parsedown": "^1.7",
|
"erusev/parsedown": "^1.7",
|
||||||
"symfony/console": "^5.4",
|
"symfony/console": "^5.4",
|
||||||
"pear/net_dns2": "^1.5"
|
"pear/net_dns2": "^1.5",
|
||||||
|
"amnuts/opcache-gui": "^3.4"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9",
|
"phpunit/phpunit": "^9",
|
||||||
|
|||||||
866
composer.lock
generated
866
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -51,7 +51,7 @@ $id = (int)Request::any('id');
|
|||||||
|
|
||||||
if ($page == 'overview' || $page == 'domains') {
|
if ($page == 'overview' || $page == 'domains') {
|
||||||
if ($action == '') {
|
if ($action == '') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_domains::domains");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_domains::domains");
|
||||||
|
|
||||||
$parentdomain_id = (int)Request::any('pid', '0');
|
$parentdomain_id = (int)Request::any('pid', '0');
|
||||||
|
|
||||||
@@ -73,10 +73,17 @@ if ($page == 'overview' || $page == 'domains') {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('user/table.html.twig', [
|
$table_tpl = 'table.html.twig';
|
||||||
|
if ($collection->count() == 0) {
|
||||||
|
$table_tpl = 'table-note.html.twig';
|
||||||
|
}
|
||||||
|
UI::view('user/' . $table_tpl, [
|
||||||
'listing' => Listing::format($collection, $domain_list_data, 'domain_list'),
|
'listing' => Listing::format($collection, $domain_list_data, 'domain_list'),
|
||||||
'actions_links' => $actions_links,
|
'actions_links' => $actions_links,
|
||||||
'entity_info' => lng('domains.description')
|
'entity_info' => lng('domains.description'),
|
||||||
|
// alert-box
|
||||||
|
'type' => 'warning',
|
||||||
|
'alert_msg' => lng('domains.nodomainsassignedbyadmin')
|
||||||
]);
|
]);
|
||||||
} elseif ($action == 'delete' && $id != 0) {
|
} elseif ($action == 'delete' && $id != 0) {
|
||||||
try {
|
try {
|
||||||
@@ -130,6 +137,7 @@ if ($page == 'overview' || $page == 'domains') {
|
|||||||
AND `parentdomainid` = '0'
|
AND `parentdomainid` = '0'
|
||||||
AND `email_only` = '0'
|
AND `email_only` = '0'
|
||||||
AND `caneditdomain` = '1'
|
AND `caneditdomain` = '1'
|
||||||
|
AND `deactivated` = '0'
|
||||||
ORDER BY `domain` ASC");
|
ORDER BY `domain` ASC");
|
||||||
Database::pexecute($stmt, [
|
Database::pexecute($stmt, [
|
||||||
"customerid" => $userinfo['customerid']
|
"customerid" => $userinfo['customerid']
|
||||||
@@ -139,6 +147,14 @@ if ($page == 'overview' || $page == 'domains') {
|
|||||||
$domains[$row['domain']] = $idna_convert->decode($row['domain']);
|
$domains[$row['domain']] = $idna_convert->decode($row['domain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check of there are any domains to be used
|
||||||
|
if (count($domains) <= 0) {
|
||||||
|
// no, possible direct URL access, redirect to overview
|
||||||
|
Response::redirectTo($filename, [
|
||||||
|
'page' => $page
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$aliasdomains[0] = lng('domains.noaliasdomain');
|
$aliasdomains[0] = lng('domains.noaliasdomain');
|
||||||
$domains_stmt = Database::prepare("SELECT `d`.`id`, `d`.`domain` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c`
|
$domains_stmt = Database::prepare("SELECT `d`.`id`, `d`.`domain` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c`
|
||||||
WHERE `d`.`aliasdomain` IS NULL
|
WHERE `d`.`aliasdomain` IS NULL
|
||||||
@@ -373,6 +389,23 @@ if ($page == 'overview' || $page == 'domains') {
|
|||||||
} else {
|
} else {
|
||||||
Response::standardError('domains_canteditdomain');
|
Response::standardError('domains_canteditdomain');
|
||||||
}
|
}
|
||||||
|
} elseif ($action == 'jqSpeciallogfileNote') {
|
||||||
|
$domainid = intval($_POST['id']);
|
||||||
|
$newval = intval($_POST['newval']);
|
||||||
|
try {
|
||||||
|
$json_result = SubDomains::getLocal($userinfo, [
|
||||||
|
'id' => $domainid
|
||||||
|
])->get();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
$result = json_decode($json_result, true)['data'];
|
||||||
|
if ($newval != $result['speciallogfile']) {
|
||||||
|
echo json_encode(['changed' => true, 'info' => lng('admin.speciallogwarning')]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
echo 0;
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
} elseif ($page == 'domainssleditor') {
|
} elseif ($page == 'domainssleditor') {
|
||||||
require_once __DIR__ . '/ssl_editor.php';
|
require_once __DIR__ . '/ssl_editor.php';
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'listing' => Listing::format($collection, $emaildomain_list_data, 'emaildomain_list'),
|
'listing' => Listing::format($collection, $emaildomain_list_data, 'emaildomain_list'),
|
||||||
'actions_links' => CurrentUser::canAddResource('emails') ? [
|
'actions_links' => CurrentUser::canAddResource('emails') ? [
|
||||||
[
|
[
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => $page, 'action' => 'add']),
|
'href' => $linker->getLink(['section' => 'email', 'page' => 'email_domain', 'action' => 'add']),
|
||||||
'label' => lng('emails.emails_add')
|
'label' => lng('emails.emails_add')
|
||||||
]
|
]
|
||||||
] : null,
|
] : null,
|
||||||
@@ -84,7 +84,7 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
if ($page == 'email_domain') {
|
if ($page == 'email_domain') {
|
||||||
$email_domainid = Request::any('domainid', 0);
|
$email_domainid = Request::any('domainid', 0);
|
||||||
if ($action == '') {
|
if ($action == '') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_email::emails");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_email::emails");
|
||||||
|
|
||||||
$sql_search = [];
|
$sql_search = [];
|
||||||
if ($email_domainid > 0) {
|
if ($email_domainid > 0) {
|
||||||
@@ -123,7 +123,7 @@ if ($page == 'email_domain') {
|
|||||||
}
|
}
|
||||||
if (CurrentUser::canAddResource('emails')) {
|
if (CurrentUser::canAddResource('emails')) {
|
||||||
$actions_links[] = [
|
$actions_links[] = [
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => 'email_domain', 'action' => 'add']),
|
'href' => $linker->getLink(['section' => 'email', 'page' => 'email_domain', 'action' => 'add', 'domainid' => $email_domainid]),
|
||||||
'label' => lng('emails.emails_add')
|
'label' => lng('emails.emails_add')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,11 @@ if ($page == 'email_domain') {
|
|||||||
"cid" => $userinfo['customerid']
|
"cid" => $userinfo['customerid']
|
||||||
]);
|
]);
|
||||||
$domains = [];
|
$domains = [];
|
||||||
|
$selected_domain = "";
|
||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
if ($email_domainid == $row['id']) {
|
||||||
|
$selected_domain = $row['domain'];
|
||||||
|
}
|
||||||
$domains[$row['domain']] = $idna_convert->decode($row['domain']);
|
$domains[$row['domain']] = $idna_convert->decode($row['domain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
const AREA = 'customer';
|
const AREA = 'customer';
|
||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\Api\Commands\CustomerBackups as CustomerBackups;
|
use Froxlor\Api\Commands\DataDump as DataDump;
|
||||||
use Froxlor\Api\Commands\DirOptions as DirOptions;
|
use Froxlor\Api\Commands\DirOptions as DirOptions;
|
||||||
use Froxlor\Api\Commands\DirProtections as DirProtections;
|
use Froxlor\Api\Commands\DirProtections as DirProtections;
|
||||||
use Froxlor\Customer\Customer;
|
use Froxlor\Customer\Customer;
|
||||||
@@ -282,18 +282,18 @@ if ($page == 'overview' || $page == 'htpasswds') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($page == 'backup') {
|
} elseif ($page == 'export') {
|
||||||
// redirect if this customer sub-page is hidden via settings
|
// redirect if this customer sub-page is hidden via settings
|
||||||
if (Settings::IsInList('panel.customer_hide_options', 'extras.backup')) {
|
if (Settings::IsInList('panel.customer_hide_options', 'extras.export')) {
|
||||||
Response::redirectTo('customer_index.php');
|
Response::redirectTo('customer_index.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::Get('system.backupenabled') == 1) {
|
if (Settings::Get('system.exportenabled') == 1) {
|
||||||
if ($action == 'abort') {
|
if ($action == 'abort') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "customer_extras::backup - aborted scheduled backupjob");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "customer_extras::export - aborted scheduled data export job");
|
||||||
try {
|
try {
|
||||||
CustomerBackups::getLocal($userinfo, $_POST)->delete();
|
DataDump::getLocal($userinfo, $_POST)->delete();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
@@ -302,43 +302,43 @@ if ($page == 'overview' || $page == 'htpasswds') {
|
|||||||
'action' => ''
|
'action' => ''
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
HTML::askYesNo('extras_reallydelete_backup', $filename, [
|
HTML::askYesNo('extras_reallydelete_export', $filename, [
|
||||||
'backup_job_entry' => $id,
|
'job_entry' => $id,
|
||||||
'section' => 'extras',
|
'section' => 'extras',
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'action' => $action
|
'action' => $action
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} elseif ($action == '') {
|
} elseif ($action == '') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_extras::backup");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_extras::export");
|
||||||
|
|
||||||
// check whether there is a backup-job for this customer
|
// check whether there is a backup-job for this customer
|
||||||
try {
|
try {
|
||||||
$backup_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.backups.php';
|
$export_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.export.php';
|
||||||
$collection = (new Collection(CustomerBackups::class, $userinfo));
|
$collection = (new Collection(DataDump::class, $userinfo));
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
try {
|
try {
|
||||||
CustomerBackups::getLocal($userinfo, $_POST)->add();
|
DataDump::getLocal($userinfo, $_POST)->add();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::standardSuccess('backupscheduled');
|
Response::standardSuccess('exportscheduled');
|
||||||
} else {
|
} else {
|
||||||
$pathSelect = FileDir::makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']);
|
$pathSelect = FileDir::makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']);
|
||||||
$backup_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.backup.php';
|
$export_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.export.php';
|
||||||
|
|
||||||
UI::view('user/form-datatable.html.twig', [
|
UI::view('user/form-datatable.html.twig', [
|
||||||
'formaction' => $linker->getLink(['section' => 'extras']),
|
'formaction' => $linker->getLink(['section' => 'extras']),
|
||||||
'formdata' => $backup_data['backup'],
|
'formdata' => $export_data['export'],
|
||||||
'tabledata' => Listing::format($collection, $backup_list_data, 'backup_list'),
|
'tabledata' => Listing::format($collection, $export_list_data, 'export_list'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Response::standardError('backupfunctionnotenabled');
|
Response::standardError('exportfunctionnotenabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ if ($page == 'overview' || $page == 'accounts') {
|
|||||||
if (Settings::Get('customer.ftpatdomain') == '1') {
|
if (Settings::Get('customer.ftpatdomain') == '1') {
|
||||||
$domainlist = [];
|
$domainlist = [];
|
||||||
$result_domains_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
$result_domains_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE `customerid`= :customerid");
|
WHERE `customerid`= :customerid ORDER BY `domain` ASC");
|
||||||
Database::pexecute($result_domains_stmt, [
|
Database::pexecute($result_domains_stmt, [
|
||||||
"customerid" => $userinfo['customerid']
|
"customerid" => $userinfo['customerid']
|
||||||
]);
|
]);
|
||||||
@@ -127,7 +127,6 @@ if ($page == 'overview' || $page == 'accounts') {
|
|||||||
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$domainlist[$row_domain['domain']] = $idna_convert->decode($row_domain['domain']);
|
$domainlist[$row_domain['domain']] = $idna_convert->decode($row_domain['domain']);
|
||||||
}
|
}
|
||||||
sort($domainlist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::Get('system.allow_customer_shell') == '1') {
|
if (Settings::Get('system.allow_customer_shell') == '1') {
|
||||||
|
|||||||
@@ -27,21 +27,21 @@ const AREA = 'customer';
|
|||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\Api\Commands\Customers as Customers;
|
use Froxlor\Api\Commands\Customers as Customers;
|
||||||
|
use Froxlor\Cron\TaskId;
|
||||||
use Froxlor\CurrentUser;
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\Language;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\Crypt;
|
use Froxlor\System\Crypt;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use Froxlor\Language;
|
|
||||||
use Froxlor\System\Cronjob;
|
|
||||||
use Froxlor\Cron\TaskId;
|
|
||||||
|
|
||||||
if ($action == 'logout') {
|
if ($action == 'logout') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'logged out');
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, 'logged out');
|
||||||
|
|
||||||
unset($_SESSION['userinfo']);
|
unset($_SESSION['userinfo']);
|
||||||
CurrentUser::setData();
|
CurrentUser::setData();
|
||||||
@@ -52,6 +52,7 @@ if ($action == 'logout') {
|
|||||||
if (is_array(CurrentUser::getField('switched_user'))) {
|
if (is_array(CurrentUser::getField('switched_user'))) {
|
||||||
$result = CurrentUser::getData();
|
$result = CurrentUser::getData();
|
||||||
$result = $result['switched_user'];
|
$result = $result['switched_user'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
||||||
$redirect = "admin_" . $target . ".php";
|
$redirect = "admin_" . $target . ".php";
|
||||||
@@ -65,7 +66,7 @@ if ($action == 'logout') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($page == 'overview') {
|
if ($page == 'overview') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_index");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_index");
|
||||||
|
|
||||||
$domain_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
$domain_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE `customerid` = :customerid
|
WHERE `customerid` = :customerid
|
||||||
@@ -113,15 +114,20 @@ if ($page == 'overview') {
|
|||||||
$userinfo['traffic_bytes'] = ($userinfo['traffic'] > -1) ? $userinfo['traffic'] * 1024 : -1;
|
$userinfo['traffic_bytes'] = ($userinfo['traffic'] > -1) ? $userinfo['traffic'] * 1024 : -1;
|
||||||
$userinfo['traffic_bytes_used'] = $userinfo['traffic_used'] * 1024;
|
$userinfo['traffic_bytes_used'] = $userinfo['traffic_used'] * 1024;
|
||||||
|
|
||||||
|
if (Settings::Get('system.mail_quota_enabled')) {
|
||||||
|
$userinfo['email_quota_bytes'] = ($userinfo['email_quota'] > -1) ? $userinfo['email_quota'] * 1024 : -1;
|
||||||
|
$userinfo['email_quota_bytes_used'] = $userinfo['email_quota_used'] * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
if ($usages) {
|
if ($usages) {
|
||||||
$userinfo['diskspace_bytes_used'] = $usages['webspace'] * 1024;
|
$userinfo['diskspace_bytes_used'] = $usages['webspace'] * 1024;
|
||||||
$userinfo['mailspace_used'] = $usages['mail'] * 1024;
|
$userinfo['mailspace_used'] = $usages['mail'] * 1024;
|
||||||
$userinfo['dbspace_used'] = $usages['mysql'] * 1024;
|
$userinfo['dbspace_used'] = $usages['mysql'] * 1024;
|
||||||
$userinfo['total_bytes_used'] = ($usages['webspace'] + $usages['mail'] + $usages['mysql']) * 1024;
|
$userinfo['total_bytes_used'] = ($usages['webspace'] + $usages['mail'] + $usages['mysql']) * 1024;
|
||||||
} else {
|
} else {
|
||||||
$userinfo['diskspace_bytes_used'] = 0;
|
$userinfo['diskspace_bytes_used'] = 0;
|
||||||
$userinfo['total_bytes_used'] = 0;
|
$userinfo['total_bytes_used'] = 0;
|
||||||
$userinfo['mailspace_used'] = 0;
|
$userinfo['mailspace_used'] = 0;
|
||||||
$userinfo['dbspace_used'] = 0;
|
$userinfo['dbspace_used'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,141 +136,138 @@ if ($page == 'overview') {
|
|||||||
'domains' => $domainArray,
|
'domains' => $domainArray,
|
||||||
'stdsubdomain' => $stdsubdomain
|
'stdsubdomain' => $stdsubdomain
|
||||||
]);
|
]);
|
||||||
} elseif ($page == 'change_password') {
|
} elseif ($page == 'profile') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
$languages = Language::getLanguages();
|
||||||
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
|
||||||
|
|
||||||
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) {
|
if (!empty($_POST)) {
|
||||||
Response::standardError('oldpasswordnotcorrect');
|
if ($_POST['send'] == 'changepassword') {
|
||||||
}
|
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
||||||
|
|
||||||
try {
|
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) {
|
||||||
$new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
|
Response::standardError('oldpasswordnotcorrect');
|
||||||
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
|
}
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($old_password == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.old_password'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.new_password'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password_confirm == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.new_password_confirm'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password != $new_password_confirm) {
|
|
||||||
Response::standardError('newpasswordconfirmerror');
|
|
||||||
} else {
|
|
||||||
// Update user password
|
|
||||||
try {
|
try {
|
||||||
Customers::getLocal($userinfo, [
|
$new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
|
||||||
'id' => $userinfo['customerid'],
|
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
|
||||||
'new_customer_password' => $new_password
|
|
||||||
])->update();
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed password');
|
|
||||||
|
|
||||||
// Update ftp password
|
if ($old_password == '') {
|
||||||
if (isset($_POST['change_main_ftp']) && $_POST['change_main_ftp'] == 'true') {
|
Response::standardError([
|
||||||
$cryptPassword = Crypt::makeCryptPassword($new_password);
|
'stringisempty',
|
||||||
$stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "`
|
'changepassword.old_password'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password == '') {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'changepassword.new_password'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password_confirm == '') {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'changepassword.new_password_confirm'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password != $new_password_confirm) {
|
||||||
|
Response::standardError('newpasswordconfirmerror');
|
||||||
|
} else {
|
||||||
|
// Update user password
|
||||||
|
try {
|
||||||
|
Customers::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['customerid'],
|
||||||
|
'new_customer_password' => $new_password
|
||||||
|
])->update();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed password');
|
||||||
|
|
||||||
|
// Update ftp password
|
||||||
|
if (isset($_POST['change_main_ftp']) && $_POST['change_main_ftp'] == 'true') {
|
||||||
|
$cryptPassword = Crypt::makeCryptPassword($new_password);
|
||||||
|
$stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "`
|
||||||
SET `password` = :password
|
SET `password` = :password
|
||||||
WHERE `customerid` = :customerid
|
WHERE `customerid` = :customerid
|
||||||
AND `username` = :username");
|
AND `username` = :username");
|
||||||
$params = [
|
$params = [
|
||||||
"password" => $cryptPassword,
|
"password" => $cryptPassword,
|
||||||
"customerid" => $userinfo['customerid'],
|
"customerid" => $userinfo['customerid'],
|
||||||
"username" => $userinfo['loginname']
|
"username" => $userinfo['loginname']
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params);
|
Database::pexecute($stmt, $params);
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed main ftp password');
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed main ftp password');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update statistics password
|
// Update statistics password
|
||||||
if (isset($_POST['change_stats']) && $_POST['change_stats'] == 'true') {
|
if (isset($_POST['change_stats']) && $_POST['change_stats'] == 'true') {
|
||||||
$new_stats_password = Crypt::makeCryptPassword($new_password, true);
|
$new_stats_password = Crypt::makeCryptPassword($new_password, true);
|
||||||
|
|
||||||
$stmt = Database::prepare("UPDATE `" . TABLE_PANEL_HTPASSWDS . "`
|
$stmt = Database::prepare("UPDATE `" . TABLE_PANEL_HTPASSWDS . "`
|
||||||
SET `password` = :password
|
SET `password` = :password
|
||||||
WHERE `customerid` = :customerid
|
WHERE `customerid` = :customerid
|
||||||
AND `username` = :username");
|
AND `username` = :username");
|
||||||
$params = [
|
$params = [
|
||||||
"password" => $new_stats_password,
|
"password" => $new_stats_password,
|
||||||
"customerid" => $userinfo['customerid'],
|
"customerid" => $userinfo['customerid'],
|
||||||
"username" => $userinfo['loginname']
|
"username" => $userinfo['loginname']
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params);
|
Database::pexecute($stmt, $params);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Response::redirectTo($filename);
|
||||||
|
}
|
||||||
|
} elseif ($_POST['send'] == 'changetheme') {
|
||||||
|
if (Settings::Get('panel.allow_theme_change_customer') == 1) {
|
||||||
|
$theme = Validate::validate($_POST['theme'], 'theme');
|
||||||
|
try {
|
||||||
|
Customers::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['customerid'],
|
||||||
|
'theme' => $theme
|
||||||
|
])->update();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default theme to '" . $theme . "'");
|
||||||
|
}
|
||||||
|
Response::redirectTo($filename);
|
||||||
|
} elseif ($_POST['send'] == 'changelanguage') {
|
||||||
|
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
||||||
|
if (isset($languages[$def_language])) {
|
||||||
|
try {
|
||||||
|
Customers::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['customerid'],
|
||||||
|
'def_language' => $def_language
|
||||||
|
])->update();
|
||||||
|
CurrentUser::setField('language', $def_language);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default language to '" . $def_language . "'");
|
||||||
Response::redirectTo($filename);
|
Response::redirectTo($filename);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UI::view('user/change_password.html.twig');
|
// change theme
|
||||||
}
|
$default_theme = Settings::Get('panel.default_theme');
|
||||||
} elseif ($page == 'change_language') {
|
if ($userinfo['theme'] != '') {
|
||||||
$languages = Language::getLanguages();
|
$default_theme = $userinfo['theme'];
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
|
||||||
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
|
||||||
if (isset($languages[$def_language])) {
|
|
||||||
try {
|
|
||||||
Customers::getLocal($userinfo, [
|
|
||||||
'id' => $userinfo['customerid'],
|
|
||||||
'def_language' => $def_language
|
|
||||||
])->update();
|
|
||||||
CurrentUser::setField('language', $def_language);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default language to '" . $def_language . "'");
|
$themes_avail = UI::getThemes();
|
||||||
Response::redirectTo($filename);
|
|
||||||
} else {
|
// change language
|
||||||
$default_lang = Settings::Get('panel.standardlanguage');
|
$default_lang = Settings::Get('panel.standardlanguage');
|
||||||
if ($userinfo['def_language'] != '') {
|
if ($userinfo['def_language'] != '') {
|
||||||
$default_lang = $userinfo['def_language'];
|
$default_lang = $userinfo['def_language'];
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('user/change_language.html.twig', [
|
UI::view('user/profile.html.twig', [
|
||||||
'languages' => $languages,
|
|
||||||
'default_lang' => $default_lang
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} elseif ($page == 'change_theme') {
|
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
|
||||||
$theme = Validate::validate($_POST['theme'], 'theme');
|
|
||||||
try {
|
|
||||||
Customers::getLocal($userinfo, [
|
|
||||||
'id' => $userinfo['customerid'],
|
|
||||||
'theme' => $theme
|
|
||||||
])->update();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default theme to '" . $theme . "'");
|
|
||||||
Response::redirectTo($filename);
|
|
||||||
} else {
|
|
||||||
$default_theme = Settings::Get('panel.default_theme');
|
|
||||||
if ($userinfo['theme'] != '') {
|
|
||||||
$default_theme = $userinfo['theme'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$themes_avail = UI::getThemes();
|
|
||||||
|
|
||||||
UI::view('user/change_theme.html.twig', [
|
|
||||||
'themes' => $themes_avail,
|
'themes' => $themes_avail,
|
||||||
'default_theme' => $default_theme
|
'default_theme' => $default_theme,
|
||||||
|
'languages' => $languages,
|
||||||
|
'default_lang' => $default_lang,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} elseif ($page == 'send_error_report' && Settings::Get('system.allow_error_report_customer') == '1') {
|
} elseif ($page == 'send_error_report' && Settings::Get('system.allow_error_report_customer') == '1') {
|
||||||
|
|||||||
155
index.php
155
index.php
@@ -26,6 +26,7 @@
|
|||||||
const AREA = 'login';
|
const AREA = 'login';
|
||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
|
use Froxlor\Api\FroxlorRPC;
|
||||||
use Froxlor\CurrentUser;
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Customer\Customer;
|
use Froxlor\Customer\Customer;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
@@ -37,10 +38,10 @@ use Froxlor\PhpHelper;
|
|||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Crypt;
|
use Froxlor\System\Crypt;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\User;
|
use Froxlor\User;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use Froxlor\Language;
|
|
||||||
|
|
||||||
if ($action == '') {
|
if ($action == '') {
|
||||||
$action = 'login';
|
$action = 'login';
|
||||||
@@ -53,9 +54,15 @@ if ($action == '2fa_entercode') {
|
|||||||
Response::redirectTo('index.php');
|
Response::redirectTo('index.php');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
$smessage = isset($_GET['showmessage']) ? (int)$_GET['showmessage'] : 0;
|
||||||
|
$message = "";
|
||||||
|
if ($smessage > 0) {
|
||||||
|
$message = lng('error.2fa_wrongcode');
|
||||||
|
}
|
||||||
// show template to enter code
|
// show template to enter code
|
||||||
UI::view('login/enter2fa.html.twig', [
|
UI::view('login/enter2fa.html.twig', [
|
||||||
'pagetitle' => lng('login.2fa')
|
'pagetitle' => lng('login.2fa'),
|
||||||
|
'message' => $message
|
||||||
]);
|
]);
|
||||||
} elseif ($action == '2fa_verify') {
|
} elseif ($action == '2fa_verify') {
|
||||||
// verify code from 2fa code-enter form
|
// verify code from 2fa code-enter form
|
||||||
@@ -68,25 +75,25 @@ if ($action == '2fa_entercode') {
|
|||||||
// verify entered code
|
// verify entered code
|
||||||
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
||||||
$result = ($_SESSION['secret_2fa'] == 'email' ? true : $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3));
|
$result = ($_SESSION['secret_2fa'] == 'email' ? true : $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3));
|
||||||
|
// get user-data
|
||||||
|
$table = $_SESSION['uidtable_2fa'];
|
||||||
|
$field = $_SESSION['uidfield_2fa'];
|
||||||
|
$uid = $_SESSION['uid_2fa'];
|
||||||
|
$isadmin = $_SESSION['unfo_2fa'];
|
||||||
// either the code is valid when using authenticator-app, or we will select userdata by id and entered code
|
// either the code is valid when using authenticator-app, or we will select userdata by id and entered code
|
||||||
// which is temporarily stored for the customer when using email-2fa
|
// which is temporarily stored for the customer when using email-2fa
|
||||||
if ($result) {
|
if ($result) {
|
||||||
// get user-data
|
|
||||||
$table = $_SESSION['uidtable_2fa'];
|
|
||||||
$field = $_SESSION['uidfield_2fa'];
|
|
||||||
$uid = $_SESSION['uid_2fa'];
|
|
||||||
$isadmin = $_SESSION['unfo_2fa'];
|
|
||||||
$sel_param = [
|
$sel_param = [
|
||||||
'uid' => $uid
|
'uid' => $uid
|
||||||
];
|
];
|
||||||
if ($_SESSION['secret_2fa'] == 'email') {
|
if ($_SESSION['secret_2fa'] == 'email') {
|
||||||
// verify code by selecting user by id and the temp. stored code,
|
// verify code by selecting user by id and the temp. stored code,
|
||||||
// so only if it's the correct code, we get the user-data
|
// so only if it's the correct code, we get the user-data
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM $table WHERE `" . $field . "` = :uid AND `data_2fa` = :code");
|
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid AND `data_2fa` = :code");
|
||||||
$sel_param['code'] = $code;
|
$sel_param['code'] = $code;
|
||||||
} else {
|
} else {
|
||||||
// Authenticator-verification has already happened at this point, so just get the user-data
|
// Authenticator-verification has already happened at this point, so just get the user-data
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM $table WHERE `" . $field . "` = :uid");
|
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid");
|
||||||
}
|
}
|
||||||
$userinfo = Database::pexecute_first($sel_stmt, $sel_param);
|
$userinfo = Database::pexecute_first($sel_stmt, $sel_param);
|
||||||
// whoops, no (valid) user? Start again
|
// whoops, no (valid) user? Start again
|
||||||
@@ -108,19 +115,54 @@ if ($action == '2fa_entercode') {
|
|||||||
|
|
||||||
// when using email-2fa, remove the one-time-code
|
// when using email-2fa, remove the one-time-code
|
||||||
if ($userinfo['type_2fa'] == '1') {
|
if ($userinfo['type_2fa'] == '1') {
|
||||||
$del_stmt = Database::prepare("UPDATE $table SET `data_2fa` = '' WHERE `" . $field . "` = :uid");
|
$del_stmt = Database::prepare("UPDATE " . $table . " SET `data_2fa` = '' WHERE `" . $field . "` = :uid");
|
||||||
$userinfo = Database::pexecute_first($del_stmt, [
|
$userinfo = Database::pexecute_first($del_stmt, [
|
||||||
'uid' => $uid
|
'uid' => $uid
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
// wrong 2fa code - treat like "wrong password"
|
||||||
|
$stmt = Database::prepare("
|
||||||
|
UPDATE " . $table . "
|
||||||
|
SET `lastlogin_fail`= :lastlogin_fail, `loginfail_count`=`loginfail_count`+1
|
||||||
|
WHERE `" . $field . "`= :uid
|
||||||
|
");
|
||||||
|
Database::pexecute($stmt, [
|
||||||
|
"lastlogin_fail" => time(),
|
||||||
|
"uid" => $uid
|
||||||
|
]);
|
||||||
|
|
||||||
|
// get data for processing further
|
||||||
|
$stmt = Database::prepare("
|
||||||
|
SELECT `loginname`, `loginfail_count`, `lastlogin_fail` FROM " . $table . "
|
||||||
|
WHERE `" . $field . "`= :uid
|
||||||
|
");
|
||||||
|
$fail_user = Database::pexecute_first($stmt, [
|
||||||
|
"uid" => $uid
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($fail_user['loginfail_count'] >= Settings::Get('login.maxloginattempts') && $fail_user['lastlogin_fail'] > (time() - Settings::Get('login.deactivatetime'))) {
|
||||||
|
// Log failed login
|
||||||
|
$rstlog = FroxlorLogger::getInstanceOf([
|
||||||
|
'loginname' => $_SERVER['REMOTE_ADDR']
|
||||||
|
]);
|
||||||
|
$rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "User '" . $fail_user['loginname'] . "' entered wrong 2fa code too often.");
|
||||||
|
unset($fail_user);
|
||||||
|
Response::redirectTo('index.php', [
|
||||||
|
'showmessage' => '3'
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
unset($fail_user);
|
||||||
|
// back to form
|
||||||
Response::redirectTo('index.php', [
|
Response::redirectTo('index.php', [
|
||||||
'showmessage' => '2'
|
'action' => '2fa_entercode',
|
||||||
|
'showmessage' => '1'
|
||||||
]);
|
]);
|
||||||
exit();
|
exit();
|
||||||
} elseif ($action == 'login') {
|
} elseif ($action == 'login') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (!empty($_POST)) {
|
||||||
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
||||||
$password = Validate::validate($_POST['password'], 'password');
|
$password = Validate::validate($_POST['password'], 'password');
|
||||||
|
|
||||||
@@ -390,13 +432,18 @@ if ($action == '2fa_entercode') {
|
|||||||
}
|
}
|
||||||
$lastqrystr = "";
|
$lastqrystr = "";
|
||||||
if (isset($_REQUEST['qrystr']) && $_REQUEST['qrystr'] != "") {
|
if (isset($_REQUEST['qrystr']) && $_REQUEST['qrystr'] != "") {
|
||||||
$lastqrystr = htmlspecialchars($_REQUEST['qrystr'], ENT_QUOTES);
|
$lastqrystr = urlencode($_REQUEST['qrystr']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($lastscript)) {
|
||||||
|
$_SESSION['lastscript'] = $lastscript;
|
||||||
|
}
|
||||||
|
if (!empty($lastqrystr)) {
|
||||||
|
$_SESSION['lastqrystr'] = $lastqrystr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('login/login.html.twig', [
|
UI::view('login/login.html.twig', [
|
||||||
'pagetitle' => 'Login',
|
'pagetitle' => 'Login',
|
||||||
'lastscript' => $lastscript,
|
|
||||||
'lastqrystr' => $lastqrystr,
|
|
||||||
'upd_in_progress' => $update_in_progress,
|
'upd_in_progress' => $update_in_progress,
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
'successmsg' => $successmessage
|
'successmsg' => $successmessage
|
||||||
@@ -408,7 +455,7 @@ if ($action == 'forgotpwd') {
|
|||||||
$adminchecked = false;
|
$adminchecked = false;
|
||||||
$message = '';
|
$message = '';
|
||||||
|
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (!empty($_POST)) {
|
||||||
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
||||||
$email = Validate::validateEmail($_POST['loginemail']);
|
$email = Validate::validateEmail($_POST['loginemail']);
|
||||||
$result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "`
|
$result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "`
|
||||||
@@ -592,7 +639,7 @@ if ($action == 'forgotpwd') {
|
|||||||
|
|
||||||
UI::view('login/fpwd.html.twig', [
|
UI::view('login/fpwd.html.twig', [
|
||||||
'pagetitle' => lng('login.presend'),
|
'pagetitle' => lng('login.presend'),
|
||||||
'action' => $action,
|
'formaction' => 'index.php?action=' . $action,
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -615,7 +662,7 @@ if ($action == 'resetpwd') {
|
|||||||
$check = substr($activationcode, 40, 10);
|
$check = substr($activationcode, 40, 10);
|
||||||
|
|
||||||
if (substr(md5($third . $timestamp), 0, 10) == $check && $timestamp >= time() - 86400) {
|
if (substr(md5($third . $timestamp), 0, 10) == $check && $timestamp >= time() - 86400) {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (!empty($_POST)) {
|
||||||
$stmt = Database::prepare("SELECT `userid`, `admin` FROM `" . TABLE_PANEL_ACTIVATION . "`
|
$stmt = Database::prepare("SELECT `userid`, `admin` FROM `" . TABLE_PANEL_ACTIVATION . "`
|
||||||
WHERE `activationcode` = :activationcode");
|
WHERE `activationcode` = :activationcode");
|
||||||
$result = Database::pexecute_first($stmt, [
|
$result = Database::pexecute_first($stmt, [
|
||||||
@@ -689,9 +736,62 @@ if ($action == 'resetpwd') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// one-time link login
|
||||||
|
if ($action == 'll') {
|
||||||
|
if (!Froxlor::hasUpdates() && !Froxlor::hasDbUpdates()) {
|
||||||
|
$loginname = Request::get('ln');
|
||||||
|
$hash = Request::get('h');
|
||||||
|
if ($loginname && $hash) {
|
||||||
|
$sel_stmt = Database::prepare("
|
||||||
|
SELECT * FROM `" . TABLE_PANEL_LOGINLINKS . "`
|
||||||
|
WHERE `loginname` = :loginname AND `hash` = :hash
|
||||||
|
");
|
||||||
|
try {
|
||||||
|
$entry = Database::pexecute_first($sel_stmt, ['loginname' => $loginname, 'hash' => $hash]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$entry = false;
|
||||||
|
}
|
||||||
|
if ($entry) {
|
||||||
|
// delete entry
|
||||||
|
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_LOGINLINKS . "` WHERE `loginname` = :loginname AND `hash` = :hash");
|
||||||
|
Database::pexecute($del_stmt, ['loginname' => $loginname, 'hash' => $hash]);
|
||||||
|
if (time() <= $entry['valid_until']) {
|
||||||
|
$valid = true;
|
||||||
|
// validate source ip if specified
|
||||||
|
if (!empty($entry['allowed_from'])) {
|
||||||
|
$valid = false;
|
||||||
|
$ip_list = explode(",", $entry['allowed_from']);
|
||||||
|
if (FroxlorRPC::validateAllowedFrom($ip_list, $_SERVER['REMOTE_ADDR'])) {
|
||||||
|
$valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($valid) {
|
||||||
|
// login user / select only non-deactivated (in case the user got deactivated after generating the link)
|
||||||
|
$userinfo_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `loginname`= :loginname AND `deactivated` = 0");
|
||||||
|
try {
|
||||||
|
$userinfo = Database::pexecute_first($userinfo_stmt, [
|
||||||
|
"loginname" => $loginname
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$userinfo = false;
|
||||||
|
}
|
||||||
|
if ($userinfo) {
|
||||||
|
$userinfo['userid'] = $userinfo['customerid'];
|
||||||
|
$userinfo['adminsession'] = 0;
|
||||||
|
finishLogin($userinfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Response::redirectTo('index.php');
|
||||||
|
}
|
||||||
|
|
||||||
function finishLogin($userinfo)
|
function finishLogin($userinfo)
|
||||||
{
|
{
|
||||||
if (isset($userinfo['userid']) && $userinfo['userid'] != '') {
|
if (isset($userinfo['userid']) && $userinfo['userid'] != '') {
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($userinfo);
|
CurrentUser::setData($userinfo);
|
||||||
|
|
||||||
$language = $userinfo['def_language'] ?? Settings::Get('panel.standardlanguage');
|
$language = $userinfo['def_language'] ?? Settings::Get('panel.standardlanguage');
|
||||||
@@ -705,29 +805,34 @@ function finishLogin($userinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
$qryparams = [];
|
$qryparams = [];
|
||||||
if (isset($_POST['qrystr']) && $_POST['qrystr'] != "") {
|
if (!empty($_SESSION['lastqrystr'])) {
|
||||||
parse_str(urldecode($_POST['qrystr']), $qryparams);
|
parse_str(urldecode($_SESSION['lastqrystr']), $qryparams);
|
||||||
|
unset($_SESSION['lastqrystr']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($userinfo['adminsession'] == '1') {
|
if ($userinfo['adminsession'] == '1') {
|
||||||
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
||||||
Response::redirectTo('admin_updates.php?page=overview');
|
Response::redirectTo('admin_updates.php?page=overview');
|
||||||
} else {
|
} else {
|
||||||
if (isset($_POST['script']) && $_POST['script'] != "") {
|
if (!empty($_SESSION['lastscript'])) {
|
||||||
if (preg_match("/customer\_/", $_POST['script']) === 1) {
|
$lastscript = $_SESSION['lastscript'];
|
||||||
|
unset($_SESSION['lastscript']);
|
||||||
|
if (preg_match("/customer\_/", $lastscript) === 1) {
|
||||||
Response::redirectTo('admin_customers.php', [
|
Response::redirectTo('admin_customers.php', [
|
||||||
"page" => "customers"
|
"page" => "customers"
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
Response::redirectTo($_POST['script'], $qryparams);
|
Response::redirectTo($lastscript, $qryparams);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Response::redirectTo('admin_index.php', $qryparams);
|
Response::redirectTo('admin_index.php', $qryparams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isset($_POST['script']) && $_POST['script'] != "") {
|
if (!empty($_SESSION['lastscript'])) {
|
||||||
Response::redirectTo($_POST['script'], $qryparams);
|
$lastscript = $_SESSION['lastscript'];
|
||||||
|
unset($_SESSION['lastscript']);
|
||||||
|
Response::redirectTo($lastscript, $qryparams);
|
||||||
} else {
|
} else {
|
||||||
Response::redirectTo('customer_index.php', $qryparams);
|
Response::redirectTo('customer_index.php', $qryparams);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,6 +223,8 @@ CREATE TABLE `panel_customers` (
|
|||||||
`api_allowed` tinyint(1) NOT NULL default '1',
|
`api_allowed` tinyint(1) NOT NULL default '1',
|
||||||
`logviewenabled` tinyint(1) NOT NULL default '0',
|
`logviewenabled` tinyint(1) NOT NULL default '0',
|
||||||
`allowed_mysqlserver` text NOT NULL,
|
`allowed_mysqlserver` text NOT NULL,
|
||||||
|
`backup` int(11) NOT NULL default '1',
|
||||||
|
`access_backups` tinyint(1) NOT NULL default '1',
|
||||||
PRIMARY KEY (`customerid`),
|
PRIMARY KEY (`customerid`),
|
||||||
UNIQUE KEY `loginname` (`loginname`)
|
UNIQUE KEY `loginname` (`loginname`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
|
||||||
@@ -278,7 +280,6 @@ CREATE TABLE `panel_domains` (
|
|||||||
`phpsettingid` INT( 11 ) UNSIGNED NOT NULL DEFAULT '1',
|
`phpsettingid` INT( 11 ) UNSIGNED NOT NULL DEFAULT '1',
|
||||||
`mod_fcgid_starter` int(4) default '-1',
|
`mod_fcgid_starter` int(4) default '-1',
|
||||||
`mod_fcgid_maxrequests` int(4) default '-1',
|
`mod_fcgid_maxrequests` int(4) default '-1',
|
||||||
`ismainbutsubto` int(11) unsigned NOT NULL default '0',
|
|
||||||
`letsencrypt` tinyint(1) NOT NULL default '0',
|
`letsencrypt` tinyint(1) NOT NULL default '0',
|
||||||
`hsts` varchar(10) NOT NULL default '0',
|
`hsts` varchar(10) NOT NULL default '0',
|
||||||
`hsts_sub` tinyint(1) NOT NULL default '0',
|
`hsts_sub` tinyint(1) NOT NULL default '0',
|
||||||
@@ -555,7 +556,7 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'defaultip', '1'),
|
('system', 'defaultip', '1'),
|
||||||
('system', 'defaultsslip', ''),
|
('system', 'defaultsslip', ''),
|
||||||
('system', 'phpappendopenbasedir', '/tmp/'),
|
('system', 'phpappendopenbasedir', '/tmp/'),
|
||||||
('system', 'deactivateddocroot', ''),
|
('system', 'deactivateddocroot', '/var/www/html/froxlor/templates/misc/deactivated/'),
|
||||||
('system', 'mailpwcleartext', '0'),
|
('system', 'mailpwcleartext', '0'),
|
||||||
('system', 'last_tasks_run', '000000'),
|
('system', 'last_tasks_run', '000000'),
|
||||||
('system', 'nameservers', ''),
|
('system', 'nameservers', ''),
|
||||||
@@ -647,7 +648,7 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'letsencryptreuseold', 0),
|
('system', 'letsencryptreuseold', 0),
|
||||||
('system', 'leenabled', '0'),
|
('system', 'leenabled', '0'),
|
||||||
('system', 'leapiversion', '2'),
|
('system', 'leapiversion', '2'),
|
||||||
('system', 'backupenabled', '0'),
|
('system', 'exportenabled', '0'),
|
||||||
('system', 'dnsenabled', '0'),
|
('system', 'dnsenabled', '0'),
|
||||||
('system', 'dns_server', 'Bind'),
|
('system', 'dns_server', 'Bind'),
|
||||||
('system', 'apacheglobaldiropt', ''),
|
('system', 'apacheglobaldiropt', ''),
|
||||||
@@ -697,8 +698,15 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'distribution', ''),
|
('system', 'distribution', ''),
|
||||||
('system', 'update_channel', 'stable'),
|
('system', 'update_channel', 'stable'),
|
||||||
('system', 'updatecheck_data', ''),
|
('system', 'updatecheck_data', ''),
|
||||||
('system', 'update_notify_last', '2.0.12'),
|
('system', 'update_notify_last', '2.0.20'),
|
||||||
('system', 'traffictool', 'goaccess'),
|
('system', 'traffictool', 'goaccess'),
|
||||||
|
('system', 'req_limit_per_interval', 60),
|
||||||
|
('system', 'req_limit_interval', 60),
|
||||||
|
('backup', 'enabled', 0),
|
||||||
|
('backup', 'default_storage', '1'),
|
||||||
|
('backup', 'default_customer_access', '1'),
|
||||||
|
('backup', 'default_pgp_public_key', ''),
|
||||||
|
('backup', 'default_retention', '3'),
|
||||||
('api', 'enabled', '0'),
|
('api', 'enabled', '0'),
|
||||||
('api', 'customer_default', '1'),
|
('api', 'customer_default', '1'),
|
||||||
('2fa', 'enabled', '1'),
|
('2fa', 'enabled', '1'),
|
||||||
@@ -742,8 +750,8 @@ opcache.validate_timestamps'),
|
|||||||
('panel', 'logo_overridetheme', '0'),
|
('panel', 'logo_overridetheme', '0'),
|
||||||
('panel', 'logo_overridecustom', '0'),
|
('panel', 'logo_overridecustom', '0'),
|
||||||
('panel', 'settings_mode', '0'),
|
('panel', 'settings_mode', '0'),
|
||||||
('panel', 'version', '2.0.12'),
|
('panel', 'version', '2.0.20'),
|
||||||
('panel', 'db_version', '202302030');
|
('panel', 'db_version', '202305240');
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_tasks`;
|
DROP TABLE IF EXISTS `panel_tasks`;
|
||||||
@@ -912,7 +920,8 @@ INSERT INTO `cronjobs_run` (`id`, `module`, `cronfile`, `cronclass`, `interval`,
|
|||||||
(3, 'froxlor/reports', 'usage_report', '\\Froxlor\\Cron\\Traffic\\ReportsCron', '1 DAY', '1', 'cron_usage_report'),
|
(3, 'froxlor/reports', 'usage_report', '\\Froxlor\\Cron\\Traffic\\ReportsCron', '1 DAY', '1', 'cron_usage_report'),
|
||||||
(4, 'froxlor/core', 'mailboxsize', '\\Froxlor\\Cron\\System\\MailboxsizeCron', '6 HOUR', '1', 'cron_mailboxsize'),
|
(4, 'froxlor/core', 'mailboxsize', '\\Froxlor\\Cron\\System\\MailboxsizeCron', '6 HOUR', '1', 'cron_mailboxsize'),
|
||||||
(5, 'froxlor/letsencrypt', 'letsencrypt', '\\Froxlor\\Cron\\Http\\LetsEncrypt\\AcmeSh', '5 MINUTE', '0', 'cron_letsencrypt'),
|
(5, 'froxlor/letsencrypt', 'letsencrypt', '\\Froxlor\\Cron\\Http\\LetsEncrypt\\AcmeSh', '5 MINUTE', '0', 'cron_letsencrypt'),
|
||||||
(6, 'froxlor/backup', 'backup', '\\Froxlor\\Cron\\System\\BackupCron', '1 DAY', '0', 'cron_backup');
|
(6, 'froxlor/export', 'export', '\\Froxlor\\Cron\\System\\ExportCron', '1 HOUR', '0', 'cron_export'),
|
||||||
|
(7, 'froxlor/backup', 'backup', '\\Froxlor\\Cron\\Backup\\BackupCron', '1 DAY', '0', 'cron_backup');
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `ftp_quotalimits`;
|
DROP TABLE IF EXISTS `ftp_quotalimits`;
|
||||||
@@ -983,7 +992,9 @@ CREATE TABLE IF NOT EXISTS `domain_ssl_settings` (
|
|||||||
`ssl_cert_chainfile` mediumtext,
|
`ssl_cert_chainfile` mediumtext,
|
||||||
`ssl_csr_file` mediumtext,
|
`ssl_csr_file` mediumtext,
|
||||||
`ssl_fullchain_file` mediumtext,
|
`ssl_fullchain_file` mediumtext,
|
||||||
`expirationdate` datetime DEFAULT NULL,
|
`validfromdate` datetime DEFAULT NULL,
|
||||||
|
`validtodate` datetime DEFAULT NULL,
|
||||||
|
`issuer` varchar(255) NOT NULL default '',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY (`domainid`)
|
UNIQUE KEY (`domainid`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
@@ -1048,4 +1059,48 @@ CREATE TABLE `panel_usercolumns` (
|
|||||||
KEY adminid (adminid),
|
KEY adminid (adminid),
|
||||||
KEY customerid (customerid)
|
KEY customerid (customerid)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
|
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `panel_loginlinks`;
|
||||||
|
CREATE TABLE `panel_loginlinks` (
|
||||||
|
`hash` varchar(500) NOT NULL,
|
||||||
|
`loginname` varchar(50) NOT NULL,
|
||||||
|
`valid_until` int(15) NOT NULL,
|
||||||
|
`allowed_from` text NOT NULL,
|
||||||
|
UNIQUE KEY `loginname` (`loginname`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
|
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `panel_backup_storages`;
|
||||||
|
CREATE TABLE `panel_backup_storages` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`description` varchar(255) NOT NULL,
|
||||||
|
`type` varchar(255) NOT NULL DEFAULT 'local',
|
||||||
|
`region` varchar(255) NULL,
|
||||||
|
`bucket` varchar(255) NULL,
|
||||||
|
`destination_path` varchar(255) NOT NULL,
|
||||||
|
`hostname` varchar(255) NULL,
|
||||||
|
`username` varchar(255) NULL,
|
||||||
|
`password` text,
|
||||||
|
`pgp_public_key` text,
|
||||||
|
`retention` int(3) NOT NULL DEFAULT 3,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
|
|
||||||
|
INSERT INTO `panel_backup_storages` (`id`, `description`, `destination_path`) VALUES
|
||||||
|
(1, 'Local backup storage', '/var/customers/backups');
|
||||||
|
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `panel_backups`;
|
||||||
|
CREATE TABLE `panel_backups` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`adminid` int(11) NOT NULL,
|
||||||
|
`customerid` int(11) NOT NULL,
|
||||||
|
`loginname` varchar(255) NOT NULL,
|
||||||
|
`size` bigint(20) NOT NULL,
|
||||||
|
`storage_id` int(11) NOT NULL,
|
||||||
|
`filename` varchar(255) NOT NULL,
|
||||||
|
`created_at` int(15) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
FROXLORSQL;
|
FROXLORSQL;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Froxlor\Http\RateLimiter;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\Install\Install;
|
use Froxlor\Install\Install;
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ require dirname(__DIR__) . '/lib/tables.inc.php';
|
|||||||
// init twig
|
// init twig
|
||||||
UI::initTwig(true);
|
UI::initTwig(true);
|
||||||
UI::sendHeaders();
|
UI::sendHeaders();
|
||||||
|
RateLimiter::run(true);
|
||||||
|
|
||||||
$installer = new Install();
|
$installer = new Install();
|
||||||
$installer->handle();
|
$installer->handle();
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\FileDir;
|
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Settings;
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Install\Update;
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\IPTools;
|
use Froxlor\System\IPTools;
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\FileDir;
|
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Settings;
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Install\Update;
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
|
||||||
if (!defined('_CRON_UPDATE')) {
|
if (!defined('_CRON_UPDATE')) {
|
||||||
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
|
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
|
||||||
@@ -82,7 +82,7 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` DROP COLUMN `domains_see_all`;");
|
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` DROP COLUMN `domains_see_all`;");
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
Update::showUpdateStep("Checking for multiple mysql-servers to allow acccess to customers for existing databases");
|
Update::showUpdateStep("Checking for multiple mysql-servers to allow access to customers for existing databases");
|
||||||
$dbservers_stmt = Database::query("
|
$dbservers_stmt = Database::query("
|
||||||
SELECT `customerid`,
|
SELECT `customerid`,
|
||||||
GROUP_CONCAT(DISTINCT `dbserver` SEPARATOR ',') as allowed_mysqlserver
|
GROUP_CONCAT(DISTINCT `dbserver` SEPARATOR ',') as allowed_mysqlserver
|
||||||
@@ -93,7 +93,8 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
if (isset($dbserver['allowed_mysqlserver']) && !empty($dbserver['allowed_mysqlserver'])) {
|
if (isset($dbserver['allowed_mysqlserver']) && !empty($dbserver['allowed_mysqlserver'])) {
|
||||||
$allowed_mysqlserver = json_encode(explode(",", $dbserver['allowed_mysqlserver']));
|
$allowed_mysqlserver = json_encode(explode(",", $dbserver['allowed_mysqlserver']));
|
||||||
Database::pexecute($upd_stmt, ['allowed_mysql_server' => $allowed_mysqlserver, 'customerid' => $dbserver['customerid']]);
|
Database::pexecute($upd_stmt,
|
||||||
|
['allowed_mysql_server' => $allowed_mysqlserver, 'customerid' => $dbserver['customerid']]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
@@ -140,7 +141,8 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
// none of the files existed
|
// none of the files existed
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
} else {
|
} else {
|
||||||
Update::lastStepStatus(1, 'manual commands needed', 'Please run the following commands manually:<br><pre>' . $del_list . '</pre>');
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +226,8 @@ EOF;
|
|||||||
} else {
|
} else {
|
||||||
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
||||||
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
||||||
Update::lastStepStatus(1, 'manual commands needed', 'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
||||||
}
|
}
|
||||||
|
|
||||||
Froxlor::updateToDbVersion('202212060');
|
Froxlor::updateToDbVersion('202212060');
|
||||||
@@ -283,7 +286,8 @@ EOF;
|
|||||||
} else {
|
} else {
|
||||||
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
||||||
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
||||||
Update::lastStepStatus(1, 'manual commands needed', 'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Froxlor::updateToVersion('2.0.4');
|
Froxlor::updateToVersion('2.0.4');
|
||||||
@@ -323,7 +327,7 @@ if (Froxlor::isDatabaseVersion('202212060')) {
|
|||||||
$system_letsencryptchallengepath_upd = isset($_POST['system_letsencryptchallengepath_upd']) ? $_POST['system_letsencryptchallengepath_upd'] : $acmesh_challenge_dir;
|
$system_letsencryptchallengepath_upd = isset($_POST['system_letsencryptchallengepath_upd']) ? $_POST['system_letsencryptchallengepath_upd'] : $acmesh_challenge_dir;
|
||||||
if ($acmesh_challenge_dir != $system_letsencryptchallengepath_upd) {
|
if ($acmesh_challenge_dir != $system_letsencryptchallengepath_upd) {
|
||||||
Settings::Set('system.letsencryptchallengepath', $system_letsencryptchallengepath_upd);
|
Settings::Set('system.letsencryptchallengepath', $system_letsencryptchallengepath_upd);
|
||||||
if ((int) Settings::Get('system.leenabled') == 1) {
|
if ((int)Settings::Get('system.leenabled') == 1) {
|
||||||
// create JSON string for --apply
|
// create JSON string for --apply
|
||||||
$dist = Settings::Get('system.distribution');
|
$dist = Settings::Get('system.distribution');
|
||||||
$webserver = Settings::Get('system.webserver');
|
$webserver = Settings::Get('system.webserver');
|
||||||
@@ -400,3 +404,96 @@ if (Froxlor::isFroxlorVersion('2.0.11')) {
|
|||||||
Update::showUpdateStep("Updating from 2.0.11 to 2.0.12", false);
|
Update::showUpdateStep("Updating from 2.0.11 to 2.0.12", false);
|
||||||
Froxlor::updateToVersion('2.0.12');
|
Froxlor::updateToVersion('2.0.12');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.12')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.12 to 2.0.13", false);
|
||||||
|
Froxlor::updateToVersion('2.0.13');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202302030')) {
|
||||||
|
Update::showUpdateStep("Correcting language mapping of templates created pre 2.0.x");
|
||||||
|
// languages from 0.10.x
|
||||||
|
$language_mapping_comp = [
|
||||||
|
'de' => 'Deutsch',
|
||||||
|
'en' => 'English',
|
||||||
|
'fr' => 'Français',
|
||||||
|
'pt' => 'Português',
|
||||||
|
'it' => 'Italiano',
|
||||||
|
'nl' => 'Nederlands',
|
||||||
|
'se' => 'Svenska',
|
||||||
|
'cz' => 'Česká republika'
|
||||||
|
];
|
||||||
|
$upd_tpl_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET `language` = :iso WHERE `language` = :lng");
|
||||||
|
foreach ($language_mapping_comp as $iso => $lang) {
|
||||||
|
Database::pexecute($upd_tpl_stmt, ['iso' => $iso, 'lng' => $lang]);
|
||||||
|
}
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Enhancing ssl data table");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` CHANGE `expirationdate` `validtodate` datetime DEFAULT NULL;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` ADD `validfromdate` datetime DEFAULT NULL AFTER `ssl_fullchain_file`;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` ADD `issuer` varchar(255) NOT NULL default '' AFTER `validtodate`;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Filling new ssl data fields with existing certificate data");
|
||||||
|
$crt_upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` SET `validfromdate` = :validfromdate, `issuer` = :issuer WHERE `id` = :id");
|
||||||
|
$crt_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`");
|
||||||
|
Database::pexecute($crt_stmt);
|
||||||
|
while ($cert = $crt_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$cert_content = openssl_x509_parse($cert['ssl_cert_file']);
|
||||||
|
if (is_array($cert_content)) {
|
||||||
|
$validfromdate = empty($cert_content['validFrom_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validFrom_time_t']);
|
||||||
|
$issuer = $cert_content['issuer']['O'] ?? "";
|
||||||
|
Database::pexecute($crt_upd_stmt, ['validfromdate' => $validfromdate, 'issuer' => $issuer, 'id' => $cert['id']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear possible user customized columns
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_USERCOLUMNS . "` WHERE `section` = 'sslcertificates_list'");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202303150');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.13')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.13 to 2.0.14", false);
|
||||||
|
Froxlor::updateToVersion('2.0.14');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.14')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.14 to 2.0.15", false);
|
||||||
|
Froxlor::updateToVersion('2.0.15');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202303150')) {
|
||||||
|
Update::showUpdateStep("Adding new request rate limit settings");
|
||||||
|
Settings::AddNew("system.req_limit_per_interval", "60");
|
||||||
|
Settings::AddNew("system.req_limit_interval", "60");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202304260');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.15')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.15 to 2.0.16", false);
|
||||||
|
Froxlor::updateToVersion('2.0.16');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.16')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.16 to 2.0.17", false);
|
||||||
|
Froxlor::updateToVersion('2.0.17');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.17')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.17 to 2.0.18", false);
|
||||||
|
Froxlor::updateToVersion('2.0.18');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.18')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.18 to 2.0.19", false);
|
||||||
|
Froxlor::updateToVersion('2.0.19');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.19')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.19 to 2.0.20", false);
|
||||||
|
Froxlor::updateToVersion('2.0.20');
|
||||||
|
}
|
||||||
141
install/updates/froxlor/update_2.1.inc.php
Normal file
141
install/updates/froxlor/update_2.1.inc.php
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
|
||||||
|
if (!defined('_CRON_UPDATE')) {
|
||||||
|
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
|
||||||
|
header('Location: ../../../../index.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202304260')) {
|
||||||
|
Update::showUpdateStep("Cleaning domains table");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` DROP COLUMN `ismainbutsubto`;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Creating new tables and fields");
|
||||||
|
Database::query("DROP TABLE IF EXISTS `panel_loginlinks`;");
|
||||||
|
$sql = "CREATE TABLE `panel_loginlinks` (
|
||||||
|
`hash` varchar(500) NOT NULL,
|
||||||
|
`loginname` varchar(50) NOT NULL,
|
||||||
|
`valid_until` int(15) NOT NULL,
|
||||||
|
`allowed_from` text NOT NULL,
|
||||||
|
UNIQUE KEY `loginname` (`loginname`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;";
|
||||||
|
Database::query($sql);
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adjusting setting for deactivated webroot");
|
||||||
|
$current_deactivated_webroot = Settings::Get('system.deactivateddocroot');
|
||||||
|
if (empty($current_deactivated_webroot)) {
|
||||||
|
Settings::Set('system.deactivateddocroot', FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/templates/misc/deactivated/'));
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
Update::lastStepStatus(1, 'Customized setting, not changing');
|
||||||
|
}
|
||||||
|
|
||||||
|
Update::showUpdateStep("Creating new tables and fields for backups");
|
||||||
|
Database::query("DROP TABLE IF EXISTS `". TABLE_PANEL_BACKUP_STORAGES ."`;");
|
||||||
|
$sql = "CREATE TABLE `". TABLE_PANEL_BACKUP_STORAGES ."` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`description` varchar(255) NOT NULL,
|
||||||
|
`type` varchar(255) NOT NULL DEFAULT 'local',
|
||||||
|
`region` varchar(255) NULL,
|
||||||
|
`bucket` varchar(255) NULL,
|
||||||
|
`destination_path` varchar(255) NOT NULL,
|
||||||
|
`hostname` varchar(255) NULL,
|
||||||
|
`username` varchar(255) NULL,
|
||||||
|
`password` text,
|
||||||
|
`pgp_public_key` text,
|
||||||
|
`retention` int(3) NOT NULL DEFAULT 3,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;";
|
||||||
|
Database::query($sql);
|
||||||
|
Database::query("
|
||||||
|
INSERT INTO `panel_backup_storages` (`id`, `description`, `destination_path`) VALUES
|
||||||
|
(1, 'Local backup storage', '/var/customers/backups');
|
||||||
|
");
|
||||||
|
Database::query("DROP TABLE IF EXISTS `". TABLE_PANEL_BACKUPS ."`;");
|
||||||
|
$sql = "CREATE TABLE `". TABLE_PANEL_BACKUPS ."` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`adminid` int(11) NOT NULL,
|
||||||
|
`customerid` int(11) NOT NULL,
|
||||||
|
`loginname` varchar(255) NOT NULL,
|
||||||
|
`size` bigint(20) NOT NULL,
|
||||||
|
`storage_id` int(11) NOT NULL,
|
||||||
|
`filename` varchar(255) NOT NULL,
|
||||||
|
`created_at` int(15) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;";
|
||||||
|
Database::query($sql);
|
||||||
|
// add customer backup-target-storage
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `backup` int(11) NOT NULL default '1' AFTER `allowed_mysqlserver`;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `access_backups` tinyint(1) NOT NULL default '1' AFTER `backup`;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adding new backup settings");
|
||||||
|
Settings::AddNew('backup.enabled', 0);
|
||||||
|
Settings::AddNew('backup.default_storage', 1);
|
||||||
|
Settings::AddNew('backup.default_customer_access', 1);
|
||||||
|
Settings::AddNew('backup.default_pgp_public_key', '');
|
||||||
|
Settings::AddNew('backup.default_retention', 3);
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adjusting cronjobs");
|
||||||
|
Database::query("
|
||||||
|
UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET
|
||||||
|
`module`= 'froxlor/export',
|
||||||
|
`cronfile` = 'export',
|
||||||
|
`cronclass` = '\\Froxlor\\Cron\\System\\ExportCron',
|
||||||
|
`interval` = '1 HOUR',
|
||||||
|
`desc_lng_key` = 'cron_export'
|
||||||
|
WHERE `module` = 'froxlor/backup'
|
||||||
|
");
|
||||||
|
Database::query("
|
||||||
|
INSERT INTO `" . TABLE_PANEL_CRONRUNS . "` SET
|
||||||
|
`module`= 'froxlor/backup',
|
||||||
|
`cronfile` = 'backup',
|
||||||
|
`cronclass` = '\\Froxlor\\Cron\\Backup\\BackupCron',
|
||||||
|
`interval` = '1 DAY',
|
||||||
|
`isactive` = '0',
|
||||||
|
`desc_lng_key` = 'cron_backup'
|
||||||
|
");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adjusting system for data-export function");
|
||||||
|
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "`SET `varname` = 'exportenabled' WHERE `settinggroup`= 'system' AND `varname`= 'backupenabled");
|
||||||
|
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "`SET `value` = REPLACE(`value`, 'extras.backup', 'extras.export') WHERE `settinggroup` = 'panel' AND `varname` = 'customer_hide_options'");
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_USERCOLUMNS . "` WHERE `section` = 'backup_list'");
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202305240');
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ use Froxlor\Install\Update;
|
|||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
|
|
||||||
$preconfig = [
|
$preconfig = [
|
||||||
'title' => '2.x updates',
|
'title' => '2.0.x updates',
|
||||||
'fields' => []
|
'fields' => []
|
||||||
];
|
];
|
||||||
$return = [];
|
$return = [];
|
||||||
55
install/updates/preconfig/preconfig_2.1.inc.php
Normal file
55
install/updates/preconfig/preconfig_2.1.inc.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Config\ConfigParser;
|
||||||
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
|
||||||
|
$preconfig = [
|
||||||
|
'title' => '2.1.x updates',
|
||||||
|
'fields' => []
|
||||||
|
];
|
||||||
|
$return = [];
|
||||||
|
|
||||||
|
if (Update::versionInUpdate($current_version, '2.1.0-dev1')) {
|
||||||
|
// Backup
|
||||||
|
$description = 'Froxlor now comes with a backup capability (More info see [DOCS LINK].';
|
||||||
|
$question = '<strong>Would you like to enable the backup-feature (default: yes)</strong>';
|
||||||
|
$return['panel_settings_mode'] = [
|
||||||
|
'type' => 'select',
|
||||||
|
'select_var' => [
|
||||||
|
0 => 'No',
|
||||||
|
1 => 'Yes'
|
||||||
|
],
|
||||||
|
'selected' => 1,
|
||||||
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$preconfig['fields'] = $return;
|
||||||
|
return $preconfig;
|
||||||
@@ -53,7 +53,8 @@ try {
|
|||||||
if (Froxlor::isFroxlor()) {
|
if (Froxlor::isFroxlor()) {
|
||||||
|
|
||||||
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_0.10.inc.php'));
|
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_0.10.inc.php'));
|
||||||
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_2.x.inc.php'));
|
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_2.0.inc.php'));
|
||||||
|
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_2.1.inc.php'));
|
||||||
|
|
||||||
// Check Froxlor - database integrity (only happens after all updates are done, so we know the db-layout is okay)
|
// Check Froxlor - database integrity (only happens after all updates are done, so we know the db-layout is okay)
|
||||||
Update::showUpdateStep("Checking database integrity");
|
Update::showUpdateStep("Checking database integrity");
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
namespace Froxlor\Api;
|
namespace Froxlor\Api;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Froxlor\Http\RateLimiter;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use voku\helper\AntiXSS;
|
use voku\helper\AntiXSS;
|
||||||
|
|
||||||
@@ -52,6 +53,8 @@ class Api
|
|||||||
if (Settings::Get('api.enabled') != 1) {
|
if (Settings::Get('api.enabled') != 1) {
|
||||||
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
|
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RateLimiter::run();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -272,7 +272,8 @@ abstract class ApiCommand extends ApiParameter
|
|||||||
$ops = [
|
$ops = [
|
||||||
'<',
|
'<',
|
||||||
'>',
|
'>',
|
||||||
'='
|
'=',
|
||||||
|
'<>'
|
||||||
];
|
];
|
||||||
$first = true;
|
$first = true;
|
||||||
foreach ($search as $field => $valoper) {
|
foreach ($search as $field => $valoper) {
|
||||||
@@ -396,6 +397,7 @@ abstract class ApiCommand extends ApiParameter
|
|||||||
|
|
||||||
$nat_fields = [
|
$nat_fields = [
|
||||||
'`c`.`loginname`',
|
'`c`.`loginname`',
|
||||||
|
'`c`.`name`',
|
||||||
'`a`.`loginname`',
|
'`a`.`loginname`',
|
||||||
'`adminname`',
|
'`adminname`',
|
||||||
'`databasename`',
|
'`databasename`',
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ abstract class ApiParameter
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param array $params
|
* @param array|null $params
|
||||||
* optional, array of parameters (var=>value) for the command
|
* optional, array of parameters (var=>value) for the command
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function __construct($params = null)
|
public function __construct(array $params = null)
|
||||||
{
|
{
|
||||||
if (!is_null($params)) {
|
if (!is_null($params)) {
|
||||||
$params = $this->trimArray($params);
|
$params = $this->trimArray($params);
|
||||||
@@ -57,7 +57,7 @@ abstract class ApiParameter
|
|||||||
*
|
*
|
||||||
* @param array $input
|
* @param array $input
|
||||||
*
|
*
|
||||||
* @return array
|
* @return string|array
|
||||||
*/
|
*/
|
||||||
private function trimArray($input)
|
private function trimArray($input)
|
||||||
{
|
{
|
||||||
@@ -79,9 +79,9 @@ abstract class ApiParameter
|
|||||||
/**
|
/**
|
||||||
* get specific parameter which also has and unlimited-field
|
* get specific parameter which also has and unlimited-field
|
||||||
*
|
*
|
||||||
* @param string $param
|
* @param string|null $param
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param string $ul_field
|
* @param string|null $ul_field
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param bool $optional
|
* @param bool $optional
|
||||||
* default: false
|
* default: false
|
||||||
@@ -91,7 +91,7 @@ abstract class ApiParameter
|
|||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function getUlParam($param = null, $ul_field = null, $optional = false, $default = 0)
|
protected function getUlParam(string $param = null, string $ul_field = null, bool $optional = false, $default = 0)
|
||||||
{
|
{
|
||||||
$param_value = (int)$this->getParam($param, $optional, $default);
|
$param_value = (int)$this->getParam($param, $optional, $default);
|
||||||
$ul_field_value = $this->getBoolParam($ul_field, true, 0);
|
$ul_field_value = $this->getBoolParam($ul_field, true, 0);
|
||||||
@@ -102,11 +102,11 @@ abstract class ApiParameter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get specific parameter from the parameterlist;
|
* get specific parameter from the parameter list;
|
||||||
* check for existence and != empty if needed.
|
* check for existence and != empty if needed.
|
||||||
* Maybe more in the future
|
* Maybe more in the future
|
||||||
*
|
*
|
||||||
* @param string $param
|
* @param string|null $param
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param bool $optional
|
* @param bool $optional
|
||||||
* default: false
|
* default: false
|
||||||
@@ -116,7 +116,7 @@ abstract class ApiParameter
|
|||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function getParam($param = null, $optional = false, $default = '')
|
protected function getParam(string $param = null, bool $optional = false, $default = '')
|
||||||
{
|
{
|
||||||
// does it exist?
|
// does it exist?
|
||||||
if (!isset($this->cmd_params[$param])) {
|
if (!isset($this->cmd_params[$param])) {
|
||||||
@@ -128,7 +128,7 @@ abstract class ApiParameter
|
|||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
// is it empty? - test really on string, as value 0 is being seen as empty by php
|
// is it empty? - test really on string, as value 0 is being seen as empty by php
|
||||||
if ($this->cmd_params[$param] === "") {
|
if (!is_array($this->cmd_params[$param]) && trim($this->cmd_params[$param]) === "") {
|
||||||
if ($optional === false) {
|
if ($optional === false) {
|
||||||
// get module + function for better error-messages
|
// get module + function for better error-messages
|
||||||
$inmod = $this->getModFunctionString();
|
$inmod = $this->getModFunctionString();
|
||||||
@@ -142,7 +142,7 @@ abstract class ApiParameter
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* returns "module::function()" for better error-messages (missing parameter etc.)
|
* returns "module::function()" for better error-messages (missing parameter etc.)
|
||||||
* makes debugging a whole lot more comfortable
|
* makes debugging a lot more comfortable
|
||||||
*
|
*
|
||||||
* @param int $level
|
* @param int $level
|
||||||
* depth of backtrace, default 2
|
* depth of backtrace, default 2
|
||||||
@@ -152,7 +152,7 @@ abstract class ApiParameter
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function getModFunctionString($level = 1, $max_level = 5, $trace = null)
|
private function getModFunctionString(int $level = 1, int $max_level = 5, $trace = null)
|
||||||
{
|
{
|
||||||
// which class called us
|
// which class called us
|
||||||
$_class = get_called_class();
|
$_class = get_called_class();
|
||||||
@@ -174,7 +174,7 @@ abstract class ApiParameter
|
|||||||
/**
|
/**
|
||||||
* getParam wrapper for boolean parameter
|
* getParam wrapper for boolean parameter
|
||||||
*
|
*
|
||||||
* @param string $param
|
* @param string|null $param
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param bool $optional
|
* @param bool $optional
|
||||||
* default: false
|
* default: false
|
||||||
@@ -183,7 +183,7 @@ abstract class ApiParameter
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function getBoolParam($param = null, $optional = false, $default = false)
|
protected function getBoolParam(string $param = null, bool $optional = false, $default = false)
|
||||||
{
|
{
|
||||||
$_default = '0';
|
$_default = '0';
|
||||||
if ($default) {
|
if ($default) {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list admins");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list admins");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT *
|
SELECT *
|
||||||
@@ -407,7 +407,7 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get admin '" . $result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get admin '" . $result['loginname'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
||||||
@@ -584,6 +584,18 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
$theme = Settings::Get('panel.default_theme');
|
$theme = Settings::Get('panel.default_theme');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (empty(trim($name))) {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'admin.name'
|
||||||
|
], '', true);
|
||||||
|
}
|
||||||
|
if (empty(trim($email))) {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'admin.email'
|
||||||
|
], '', true);
|
||||||
|
}
|
||||||
if (!Validate::validateEmail($email)) {
|
if (!Validate::validateEmail($email)) {
|
||||||
Response::standardError('emailiswrong', $email, true);
|
Response::standardError('emailiswrong', $email, true);
|
||||||
} else {
|
} else {
|
||||||
@@ -705,7 +717,7 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
WHERE `adminid` = :adminid
|
WHERE `adminid` = :adminid
|
||||||
");
|
");
|
||||||
Database::pexecute($upd_stmt, $upd_data, true, true);
|
Database::pexecute($upd_stmt, $upd_data, true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] edited admin '" . $result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] edited admin '" . $result['loginname'] . "'");
|
||||||
|
|
||||||
// get all admin-data for return-array
|
// get all admin-data for return-array
|
||||||
$result = $this->apiCall('Admins.get', [
|
$result = $this->apiCall('Admins.get', [
|
||||||
|
|||||||
487
lib/Froxlor/Api/Commands/BackupStorages.php
Normal file
487
lib/Froxlor/Api/Commands/BackupStorages.php
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Api\Commands;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\Api\ApiCommand;
|
||||||
|
use Froxlor\Api\ResourceEntity;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
use Froxlor\UI\Response;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
class BackupStorages extends ApiCommand implements ResourceEntity
|
||||||
|
{
|
||||||
|
const SUPPORTED_TYPES = [
|
||||||
|
'local',
|
||||||
|
'ftp',
|
||||||
|
'sftp',
|
||||||
|
'rsync',
|
||||||
|
's3',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lists all backup storages 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
|
||||||
|
* @return string json-encoded array count|list
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function listing()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list backup storages");
|
||||||
|
$query_fields = [];
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT * FROM `" . TABLE_PANEL_BACKUP_STORAGES . "` ". $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit()
|
||||||
|
);
|
||||||
|
Database::pexecute($result_stmt, $query_fields, true, true);
|
||||||
|
$result = [];
|
||||||
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$result[] = $row;
|
||||||
|
}
|
||||||
|
return $this->response([
|
||||||
|
'count' => count($result),
|
||||||
|
'list' => $result
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the total number of backup storages
|
||||||
|
*
|
||||||
|
* @access admin
|
||||||
|
* @return string json-encoded response message
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function listingCount()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT COUNT(*) as num_backup_storagess
|
||||||
|
FROM `" . TABLE_PANEL_BACKUP_STORAGES . "`
|
||||||
|
");
|
||||||
|
$result = Database::pexecute_first($result_stmt, null, true, true);
|
||||||
|
if ($result) {
|
||||||
|
return $this->response($result['num_backup_storagess']);
|
||||||
|
}
|
||||||
|
$this->response(0);
|
||||||
|
}
|
||||||
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a backup storage
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* required, backup storage type
|
||||||
|
* @param string $destination_path
|
||||||
|
* required, destination path for backup storage
|
||||||
|
* @param string $description
|
||||||
|
* required, description for backup storage
|
||||||
|
* @param string $region
|
||||||
|
* optional, required if type=s3. Region for backup storage (used for S3)
|
||||||
|
* @param string $bucket
|
||||||
|
* optional, required if type=s3. Bucket for backup storage (used for S3)
|
||||||
|
* @param string $hostname
|
||||||
|
* optional, required if type != local. Hostname for backup storage
|
||||||
|
* @param string $username
|
||||||
|
* optional, required if type != local. Username for backup storage (also used as access key for S3)
|
||||||
|
* @param string $password
|
||||||
|
* optional, required if type != local. Password for backup storage (also used as secret key for S3)
|
||||||
|
* @param string $pgp_public_key
|
||||||
|
* optional, pgp public key for backup storage
|
||||||
|
* @param string $retention
|
||||||
|
* optional, retention for backup storage (default 3)
|
||||||
|
*
|
||||||
|
* @access admin
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
||||||
|
// required parameters
|
||||||
|
$type = $this->getParam('type');
|
||||||
|
$destination_path = $this->getParam('destination_path');
|
||||||
|
$description = $this->getParam('description');
|
||||||
|
|
||||||
|
// type related requirements
|
||||||
|
$optional_flags = [
|
||||||
|
'region' => true,
|
||||||
|
'bucket' => true,
|
||||||
|
'hostname' => true,
|
||||||
|
'username' => true,
|
||||||
|
'password' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!in_array($type, self::SUPPORTED_TYPES)) {
|
||||||
|
throw new Exception("Unsupported storage type: '" . $type . "'", 406);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type != 'local') {
|
||||||
|
$optional_flags['hostname'] = false;
|
||||||
|
$optional_flags['username'] = false;
|
||||||
|
$optional_flags['password'] = false;
|
||||||
|
}
|
||||||
|
if ($type == 's3') {
|
||||||
|
$optional_flags['region'] = false;
|
||||||
|
$optional_flags['bucket'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parameters
|
||||||
|
$region = $this->getParam('region', $optional_flags['region']);
|
||||||
|
$bucket = $this->getParam('bucket', $optional_flags['bucket']);
|
||||||
|
$hostname = $this->getParam('hostname', $optional_flags['hostname']);
|
||||||
|
$username = $this->getParam('username', $optional_flags['username']);
|
||||||
|
$password = $this->getParam('password', $optional_flags['password']);
|
||||||
|
$pgp_public_key = $this->getParam('pgp_public_key', true, null);
|
||||||
|
$retention = $this->getParam('retention', true, 3);
|
||||||
|
|
||||||
|
// validation
|
||||||
|
$destination_path = FileDir::makeCorrectDir(Validate::validate($destination_path, 'destination_path', Validate::REGEX_DIR, '', [], true));
|
||||||
|
// TODO: add more validation
|
||||||
|
|
||||||
|
// pgp public key validation
|
||||||
|
if (!empty($pgp_public_key)) {
|
||||||
|
// check if gnupg extension is loaded
|
||||||
|
if (!extension_loaded('gnupg')) {
|
||||||
|
Response::standardError('gnupgextensionnotavailable', '', true);
|
||||||
|
}
|
||||||
|
// check if the pgp public key is a valid key
|
||||||
|
putenv('GNUPGHOME=' . sys_get_temp_dir());
|
||||||
|
if (gnupg_import(gnupg_init(), $pgp_public_key) === false) {
|
||||||
|
Response::standardError('invalidpgppublickey', '', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// store
|
||||||
|
$stmt = Database::prepare("
|
||||||
|
INSERT INTO `" . TABLE_PANEL_BACKUP_STORAGES . "` (
|
||||||
|
`description`,
|
||||||
|
`type`,
|
||||||
|
`region`,
|
||||||
|
`bucket`,
|
||||||
|
`destination_path`,
|
||||||
|
`hostname`,
|
||||||
|
`username`,
|
||||||
|
`password`,
|
||||||
|
`pgp_public_key`,
|
||||||
|
`retention`
|
||||||
|
) VALUES (
|
||||||
|
:description,
|
||||||
|
:type,
|
||||||
|
:region,
|
||||||
|
:bucket,
|
||||||
|
:destination_path,
|
||||||
|
:hostname,
|
||||||
|
:username,
|
||||||
|
:password,
|
||||||
|
:pgp_public_key,
|
||||||
|
:retention
|
||||||
|
)
|
||||||
|
");
|
||||||
|
$params = [
|
||||||
|
"description" => $description,
|
||||||
|
"type" => $type,
|
||||||
|
"region" => $region,
|
||||||
|
"bucket" => $bucket,
|
||||||
|
"destination_path" => $destination_path,
|
||||||
|
"hostname" => $hostname,
|
||||||
|
"username" => $username,
|
||||||
|
"password" => $password,
|
||||||
|
"pgp_public_key" => $pgp_public_key,
|
||||||
|
"retention" => $retention,
|
||||||
|
];
|
||||||
|
Database::pexecute($stmt, $params, true, true);
|
||||||
|
$id = Database::lastInsertId();
|
||||||
|
|
||||||
|
// return
|
||||||
|
$result = $this->apiCall('BackupStorages.get', [
|
||||||
|
'id' => $id
|
||||||
|
]);
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] added backup storage '" . $result['description'] . "' (" . $result['type'] . ")");
|
||||||
|
return $this->response($result);
|
||||||
|
}
|
||||||
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a backup storage entry by id
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* the backup-storage-id
|
||||||
|
*
|
||||||
|
* @access admin
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function get()
|
||||||
|
{
|
||||||
|
$id = $this->getParam('id');
|
||||||
|
|
||||||
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT * FROM `" . TABLE_PANEL_BACKUP_STORAGES . "`
|
||||||
|
WHERE `id` = :id"
|
||||||
|
);
|
||||||
|
$params = [
|
||||||
|
'id' => $id
|
||||||
|
];
|
||||||
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
|
if ($result) {
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get backup storage '" . $result['description'] . "'");
|
||||||
|
return $this->response($result);
|
||||||
|
}
|
||||||
|
throw new Exception("Backup storage with " . $id . " could not be found", 404);
|
||||||
|
}
|
||||||
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update a backup storage by given id
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* required, the backup-storage-id
|
||||||
|
* @param string $type
|
||||||
|
* optional, backup storage type
|
||||||
|
* @param string $destination_path
|
||||||
|
* optional, destination path for backup storage
|
||||||
|
* @param string $description
|
||||||
|
* required, description for backup storage
|
||||||
|
* @param string $region
|
||||||
|
* optional, region for backup storage (used for S3)
|
||||||
|
* @param string $bucket
|
||||||
|
* optional, bucket for backup storage (used for S3)
|
||||||
|
* @param string $hostname
|
||||||
|
* optional, hostname for backup storage
|
||||||
|
* @param string $username
|
||||||
|
* optional, username for backup storage (also used as access key for S3)
|
||||||
|
* @param string $password
|
||||||
|
* optional, password for backup storage (also used as secret key for S3)
|
||||||
|
* @param string $pgp_public_key
|
||||||
|
* optional, pgp public key for backup storage
|
||||||
|
* @param string $retention
|
||||||
|
* optional, retention for backup storage (default 3)
|
||||||
|
*
|
||||||
|
* @access admin
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = $this->getParam('id');
|
||||||
|
|
||||||
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
||||||
|
// validation
|
||||||
|
$result = $this->apiCall('BackupStorages.get', [
|
||||||
|
'id' => $id
|
||||||
|
]);
|
||||||
|
|
||||||
|
// parameters
|
||||||
|
$description = $this->getParam('description', true, $result['description']);
|
||||||
|
$type = $this->getParam('type', true, $result['type']);
|
||||||
|
$region = $this->getParam('region', true, $result['region']);
|
||||||
|
$bucket = $this->getParam('bucket', true, $result['bucket']);
|
||||||
|
$destination_path = $this->getParam('destination_path', true, $result['destination_path']);
|
||||||
|
$hostname = $this->getParam('hostname', true, $result['hostname']);
|
||||||
|
$username = $this->getParam('username', true, $result['username']);
|
||||||
|
$password = $this->getParam('password', true, '');
|
||||||
|
$pgp_public_key = $this->getParam('pgp_public_key', true, $result['pgp_public_key']);
|
||||||
|
$retention = $this->getParam('retention', true, $result['retention']);
|
||||||
|
|
||||||
|
if (!in_array($type, self::SUPPORTED_TYPES)) {
|
||||||
|
throw new Exception("Unsupported storage type: '" . $type . "'", 406);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type != 'local') {
|
||||||
|
if (empty($hostname)) {
|
||||||
|
throw new Exception("Field 'hostname' cannot be empty", 406);
|
||||||
|
}
|
||||||
|
if (empty($username)) {
|
||||||
|
throw new Exception("Field 'username' cannot be empty", 406);
|
||||||
|
}
|
||||||
|
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||||
|
}
|
||||||
|
if ($type == 's3') {
|
||||||
|
if (empty($region)) {
|
||||||
|
throw new Exception("Field 'region' cannot be empty", 406);
|
||||||
|
}
|
||||||
|
if (empty($bucket)) {
|
||||||
|
throw new Exception("Field 'bucket' cannot be empty", 406);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation
|
||||||
|
$destination_path = FileDir::makeCorrectDir(Validate::validate($destination_path, 'destination_path', Validate::REGEX_DIR, '', [], true));
|
||||||
|
// TODO: add more validation
|
||||||
|
|
||||||
|
// pgp public key validation
|
||||||
|
if (!empty($pgp_public_key) && $pgp_public_key != $result['pgp_public_key']) {
|
||||||
|
// check if gnupg extension is loaded
|
||||||
|
if (!extension_loaded('gnupg')) {
|
||||||
|
Response::standardError('gnupgextensionnotavailable', '', true);
|
||||||
|
}
|
||||||
|
// check if the pgp public key is a valid key
|
||||||
|
putenv('GNUPGHOME=' . sys_get_temp_dir());
|
||||||
|
if (gnupg_import(gnupg_init(), $pgp_public_key) === false) {
|
||||||
|
Response::standardError('invalidpgppublickey', '', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($password)) {
|
||||||
|
$stmt = Database::prepare("UPDATE `" . TABLE_PANEL_BACKUP_STORAGES . "`
|
||||||
|
SET `password` = :password
|
||||||
|
WHERE `id` = :id
|
||||||
|
");
|
||||||
|
Database::pexecute($stmt, [
|
||||||
|
"id" => $id,
|
||||||
|
"password" => $password
|
||||||
|
], true, true);
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] updated password for backup-storage '" . $result['description'] . "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// update
|
||||||
|
$stmt = Database::prepare("
|
||||||
|
UPDATE `" . TABLE_PANEL_BACKUP_STORAGES . "`
|
||||||
|
SET `description` = :description,
|
||||||
|
`type` = :type,
|
||||||
|
`region` = :region,
|
||||||
|
`bucket` = :bucket,
|
||||||
|
`destination_path` = :destination_path,
|
||||||
|
`hostname` = :hostname,
|
||||||
|
`username` = :username,
|
||||||
|
`pgp_public_key` = :pgp_public_key,
|
||||||
|
`retention` = :retention
|
||||||
|
WHERE `id` = :id
|
||||||
|
");
|
||||||
|
$params = [
|
||||||
|
"id" => $id,
|
||||||
|
"description" => $description,
|
||||||
|
"type" => $type,
|
||||||
|
"region" => $region,
|
||||||
|
"bucket" => $bucket,
|
||||||
|
"destination_path" => $destination_path,
|
||||||
|
"hostname" => $hostname,
|
||||||
|
"username" => $username,
|
||||||
|
"pgp_public_key" => $pgp_public_key,
|
||||||
|
"retention" => $retention,
|
||||||
|
];
|
||||||
|
Database::pexecute($stmt, $params, true, true);
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] edited backup storage '" . $result['description'] . "'");
|
||||||
|
|
||||||
|
// return
|
||||||
|
$result = $this->apiCall('BackupStorages.get', [
|
||||||
|
'id' => $id
|
||||||
|
]);
|
||||||
|
return $this->response($result);
|
||||||
|
}
|
||||||
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete a backup-storage entry by id
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* required, the backup-storage-id
|
||||||
|
*
|
||||||
|
* @access admin
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = $this->getParam('id');
|
||||||
|
|
||||||
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
||||||
|
// validation
|
||||||
|
$result = $this->apiCall('BackupStorages.get', [
|
||||||
|
'id' => $id
|
||||||
|
]);
|
||||||
|
|
||||||
|
// validate no-one's using it
|
||||||
|
|
||||||
|
// settings
|
||||||
|
if ($id == Settings::Get('backup.default_storage')) {
|
||||||
|
throw new Exception("Given backup storage is currently set as default storage and cannot be deleted.", 406);
|
||||||
|
}
|
||||||
|
// customers
|
||||||
|
$sel_stmt = Database::prepare("
|
||||||
|
SELECT COUNT(*) as num_storage_users
|
||||||
|
FROM `" . TABLE_PANEL_CUSTOMERS . "`
|
||||||
|
WHERE `backup` = :id
|
||||||
|
");
|
||||||
|
$storage_users_result = Database::pexecute_first($sel_stmt, ['id' => $id]);
|
||||||
|
if ($storage_users_result && $storage_users_result['num_storage_users'] > 0) {
|
||||||
|
throw new Exception("Given backup storage is currently assigned to " . $storage_users_result['num_storage_users'] . " customers and cannot be deleted.", 406);
|
||||||
|
}
|
||||||
|
// existing backups
|
||||||
|
$sel_stmt = Database::prepare("
|
||||||
|
SELECT COUNT(*) as num_storage_backups
|
||||||
|
FROM `" . TABLE_PANEL_BACKUPS . "`
|
||||||
|
WHERE `storage_id` = :id
|
||||||
|
");
|
||||||
|
$storage_backups_result = Database::pexecute_first($sel_stmt, ['id' => $id]);
|
||||||
|
if ($storage_backups_result && $storage_backups_result['num_storage_backups'] > 0) {
|
||||||
|
throw new Exception("Given backup storage has still " . $storage_backups_result['num_storage_backups'] . " backups on it and cannot be deleted.", 406);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete
|
||||||
|
$stmt = Database::prepare("
|
||||||
|
DELETE FROM `" . TABLE_PANEL_BACKUP_STORAGES . "`
|
||||||
|
WHERE `id` = :id
|
||||||
|
");
|
||||||
|
$params = [
|
||||||
|
"id" => $id
|
||||||
|
];
|
||||||
|
Database::pexecute($stmt, $params, true, true);
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] deleted backup storage '" . $result['description'] . "'");
|
||||||
|
|
||||||
|
// return
|
||||||
|
return $this->response(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
}
|
||||||
|
}
|
||||||
211
lib/Froxlor/Api/Commands/Backups.php
Normal file
211
lib/Froxlor/Api/Commands/Backups.php
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Api\Commands;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\Api\ApiCommand;
|
||||||
|
use Froxlor\Api\ResourceEntity;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
class Backups extends ApiCommand implements ResourceEntity
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @return string json-encoded array count|list
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function listing()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin()) {
|
||||||
|
// if we're an admin, list all backups 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', [
|
||||||
|
'id' => $customerid,
|
||||||
|
'loginname' => $loginname
|
||||||
|
]);
|
||||||
|
$custom_list_result = [
|
||||||
|
$result
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$_custom_list_result = $this->apiCall('Customers.listing');
|
||||||
|
$custom_list_result = $_custom_list_result['list'];
|
||||||
|
}
|
||||||
|
$customer_ids = [];
|
||||||
|
foreach ($custom_list_result as $customer) {
|
||||||
|
$customer_ids[] = $customer['customerid'];
|
||||||
|
}
|
||||||
|
if (empty($customer_ids)) {
|
||||||
|
throw new Exception("Required resource unsatisfied.", 405);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$customer_ids = [
|
||||||
|
$this->getUserDetail('customerid')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list backups");
|
||||||
|
$query_fields = [];
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT `b`.*, `a`.`loginname` as `adminname`
|
||||||
|
FROM `" . TABLE_PANEL_BACKUPS . "` `b`
|
||||||
|
LEFT JOIN `" . TABLE_PANEL_ADMINS . "` `a` USING(`adminid`)
|
||||||
|
WHERE `b`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
||||||
|
" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit()
|
||||||
|
);
|
||||||
|
Database::pexecute($result_stmt, $query_fields, true, true);
|
||||||
|
$result = [];
|
||||||
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$result[] = $row;
|
||||||
|
}
|
||||||
|
return $this->response([
|
||||||
|
'count' => count($result),
|
||||||
|
'list' => $result
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the total number of backups for the given admin
|
||||||
|
*
|
||||||
|
* @access admin
|
||||||
|
* @return string json-encoded response message
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function listingCount()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin()) {
|
||||||
|
// if we're an admin, list all backups 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', [
|
||||||
|
'id' => $customerid,
|
||||||
|
'loginname' => $loginname
|
||||||
|
]);
|
||||||
|
$custom_list_result = [
|
||||||
|
$result
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$_custom_list_result = $this->apiCall('Customers.listing');
|
||||||
|
$custom_list_result = $_custom_list_result['list'];
|
||||||
|
}
|
||||||
|
$customer_ids = [];
|
||||||
|
foreach ($custom_list_result as $customer) {
|
||||||
|
$customer_ids[] = $customer['customerid'];
|
||||||
|
}
|
||||||
|
if (empty($customer_ids)) {
|
||||||
|
throw new Exception("Required resource unsatisfied.", 405);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$customer_ids = [
|
||||||
|
$this->getUserDetail('customerid')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT COUNT(*) as num_backups
|
||||||
|
FROM `" . TABLE_PANEL_BACKUPS . "` `b`
|
||||||
|
WHERE `b`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
||||||
|
");
|
||||||
|
$result = Database::pexecute_first($result_stmt, null, true, true);
|
||||||
|
if ($result) {
|
||||||
|
return $this->response($result['num_backups']);
|
||||||
|
}
|
||||||
|
$this->response(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You cannot add a backup entry
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
throw new Exception('You cannot add a backup entry', 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a backup entry by id
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* optional, the backup-entry-id
|
||||||
|
*
|
||||||
|
* @access admin, customers
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function get()
|
||||||
|
{
|
||||||
|
throw new Exception("@TODO", 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You cannot update a backup entry
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
throw new Exception('You cannot update a backup entry', 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete a backup entry by id
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* required, the backup-entry-id
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
throw new Exception("@TODO", 303);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -97,7 +97,7 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
if (!$has_cert) {
|
if (!$has_cert) {
|
||||||
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, true);
|
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ssl-certificate for '" . $domain['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ssl-certificate for '" . $domain['domain'] . "'");
|
||||||
$result = $this->apiCall('Certificates.get', [
|
$result = $this->apiCall('Certificates.get', [
|
||||||
'id' => $domain['id']
|
'id' => $domain['id']
|
||||||
]);
|
]);
|
||||||
@@ -127,7 +127,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
$do_verify = true;
|
$do_verify = true;
|
||||||
$expirationdate = null;
|
$validtodate = null;
|
||||||
|
$validtodate = null;
|
||||||
|
$issuer = "";
|
||||||
// no cert-file given -> forget everything
|
// no cert-file given -> forget everything
|
||||||
if ($ssl_cert_file == '') {
|
if ($ssl_cert_file == '') {
|
||||||
$ssl_key_file = '';
|
$ssl_key_file = '';
|
||||||
@@ -168,7 +170,10 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
} else {
|
} else {
|
||||||
Response::standardError('sslcertificateinvalidcert', '', true);
|
Response::standardError('sslcertificateinvalidcert', '', true);
|
||||||
}
|
}
|
||||||
$expirationdate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']);
|
// get data from certificate to store in the table
|
||||||
|
$validfromdate = empty($cert_content['validFrom_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validFrom_time_t']);
|
||||||
|
$validtodate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']);
|
||||||
|
$issuer = $cert_content['issuer']['O'] ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add/Update database entry
|
// Add/Update database entry
|
||||||
@@ -183,7 +188,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
`ssl_key_file` = :ssl_key_file,
|
`ssl_key_file` = :ssl_key_file,
|
||||||
`ssl_ca_file` = :ssl_ca_file,
|
`ssl_ca_file` = :ssl_ca_file,
|
||||||
`ssl_cert_chainfile` = :ssl_cert_chainfile,
|
`ssl_cert_chainfile` = :ssl_cert_chainfile,
|
||||||
`expirationdate` = :expirationdate
|
`validfromdate` = :validfromdate,
|
||||||
|
`validtodate` = :validtodate,
|
||||||
|
`issuer` = :issuer
|
||||||
" . $qrywhere . " `domainid`= :domainid
|
" . $qrywhere . " `domainid`= :domainid
|
||||||
");
|
");
|
||||||
$params = [
|
$params = [
|
||||||
@@ -191,7 +198,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
"ssl_key_file" => $ssl_key_file,
|
"ssl_key_file" => $ssl_key_file,
|
||||||
"ssl_ca_file" => $ssl_ca_file,
|
"ssl_ca_file" => $ssl_ca_file,
|
||||||
"ssl_cert_chainfile" => $ssl_cert_chainfile,
|
"ssl_cert_chainfile" => $ssl_cert_chainfile,
|
||||||
"expirationdate" => $expirationdate,
|
"validfromdate" => $validfromdate,
|
||||||
|
"validtodate" => $validtodate,
|
||||||
|
"issuer" => $issuer,
|
||||||
"domainid" => $domainid
|
"domainid" => $domainid
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
@@ -239,7 +248,7 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
$ssl_ca_file = $this->getParam('ssl_ca_file', true, '');
|
$ssl_ca_file = $this->getParam('ssl_ca_file', true, '');
|
||||||
$ssl_cert_chainfile = $this->getParam('ssl_cert_chainfile', true, '');
|
$ssl_cert_chainfile = $this->getParam('ssl_cert_chainfile', true, '');
|
||||||
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, false);
|
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, false);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ssl-certificate for '" . $domain['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ssl-certificate for '" . $domain['domain'] . "'");
|
||||||
$result = $this->apiCall('Certificates.get', [
|
$result = $this->apiCall('Certificates.get', [
|
||||||
'id' => $domain['id']
|
'id' => $domain['id']
|
||||||
]);
|
]);
|
||||||
@@ -299,27 +308,23 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set data from certificate
|
// Set data from certificate
|
||||||
|
$cert['isvalid'] = false;
|
||||||
|
$cert['san'] = null;
|
||||||
$cert_data = openssl_x509_parse($cert['ssl_cert_file']);
|
$cert_data = openssl_x509_parse($cert['ssl_cert_file']);
|
||||||
if ($cert_data) {
|
if ($cert_data) {
|
||||||
$cert['validfromdate'] = date('Y-m-d H:i:s', $cert_data['validFrom_time_t']);
|
|
||||||
$cert['validtodate'] = date('Y-m-d H:i:s', $cert_data['validTo_time_t']);
|
|
||||||
$cert['isvalid'] = (bool)$cert_data['validTo_time_t'] > time();
|
$cert['isvalid'] = (bool)$cert_data['validTo_time_t'] > time();
|
||||||
$cert['issuer'] = $cert_data['issuer']['O'] ?? null;
|
// Set subject alt names from certificate
|
||||||
}
|
if (isset($cert_data['extensions']['subjectAltName']) && !empty($cert_data['extensions']['subjectAltName'])) {
|
||||||
|
$SANs = explode(",", $cert_data['extensions']['subjectAltName']);
|
||||||
// Set subject alt names from certificate
|
$SANs = array_map('trim', $SANs);
|
||||||
$cert['san'] = null;
|
foreach ($SANs as $san) {
|
||||||
if (isset($cert_data['extensions']['subjectAltName']) && !empty($cert_data['extensions']['subjectAltName'])) {
|
$san = str_replace("DNS:", "", $san);
|
||||||
$SANs = explode(",", $cert_data['extensions']['subjectAltName']);
|
if ($san != $cert_data['subject']['CN'] && strpos($san, "othername:") === false) {
|
||||||
$SANs = array_map('trim', $SANs);
|
$cert['san'][] = $san;
|
||||||
foreach ($SANs as $san) {
|
}
|
||||||
$san = str_replace("DNS:", "", $san);
|
|
||||||
if ($san != $cert_data['subject']['CN'] && strpos($san, "othername:") === false) {
|
|
||||||
$cert['san'][] = $san;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[] = $cert;
|
$result[] = $cert;
|
||||||
}
|
}
|
||||||
return $this->response([
|
return $this->response([
|
||||||
@@ -465,7 +470,7 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
if ($chk['letsencrypt'] == '1') {
|
if ($chk['letsencrypt'] == '1') {
|
||||||
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $chk['domain']);
|
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $chk['domain']);
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] removed ssl-certificate for '" . $chk['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] removed ssl-certificate for '" . $chk['domain'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("Unable to determine SSL certificate. Maybe no access?", 406);
|
throw new Exception("Unable to determine SSL certificate. Maybe no access?", 406);
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// insert task to re-generate the cron.d-file
|
// insert task to re-generate the cron.d-file
|
||||||
Cronjob::inserttask(TaskId::REBUILD_CRON);
|
Cronjob::inserttask(TaskId::REBUILD_CRON);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
||||||
$result = $this->apiCall('Cronjobs.get', [
|
$result = $this->apiCall('Cronjobs.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -177,7 +177,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list cronjobs");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list cronjobs");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
AND `id`<> :stdd
|
AND `id`<> :stdd
|
||||||
");
|
");
|
||||||
$usages_stmt = Database::prepare("
|
$usages_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_DISKSPACE . "`
|
SELECT webspace, mail, mysql FROM `" . TABLE_PANEL_DISKSPACE . "`
|
||||||
WHERE `customerid` = :cid
|
WHERE `customerid` = :cid
|
||||||
ORDER BY `stamp` DESC LIMIT 1
|
ORDER BY `stamp` DESC LIMIT 1
|
||||||
");
|
");
|
||||||
@@ -109,11 +109,10 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
if ($show_usages) {
|
if ($show_usages) {
|
||||||
// get number of domains
|
// get number of domains
|
||||||
Database::pexecute($domains_stmt, [
|
$domains = Database::pexecute_first($domains_stmt, [
|
||||||
'cid' => $row['customerid'],
|
'cid' => $row['customerid'],
|
||||||
'stdd' => $row['standardsubdomain']
|
'stdd' => $row['standardsubdomain']
|
||||||
]);
|
]);
|
||||||
$domains = $domains_stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
$row['domains'] = intval($domains['domains']);
|
$row['domains'] = intval($domains['domains']);
|
||||||
// get disk-space usages for web, mysql and mail
|
// get disk-space usages for web, mysql and mail
|
||||||
$usages = Database::pexecute_first($usages_stmt, [
|
$usages = Database::pexecute_first($usages_stmt, [
|
||||||
@@ -274,6 +273,13 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
* @param array $allowed_mysqlserver
|
* @param array $allowed_mysqlserver
|
||||||
* optional, array of IDs of defined mysql-servers the customer is allowed to use,
|
* optional, array of IDs of defined mysql-servers the customer is allowed to use,
|
||||||
* default is to allow the default dbserver (id=0)
|
* default is to allow the default dbserver (id=0)
|
||||||
|
* @param int $backup
|
||||||
|
* optional, either 0 to disable backup for this customer or a backup-storage-id
|
||||||
|
* where backups are to be stored, requires change_serversettings permissions,
|
||||||
|
* default is system-setting backup.default_storage
|
||||||
|
* @param bool $access_backups
|
||||||
|
* optional, where the customer is allowed to view backups, default is system-setting
|
||||||
|
* default_customer_access
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
@@ -360,6 +366,24 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
$p_allowed_mysqlserver = [];
|
$p_allowed_mysqlserver = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->getUserDetail('change_serversettings')) {
|
||||||
|
$backup = $this->getParam('backup', true, Settings::Get('backup.default_storage'));
|
||||||
|
if ($backup > 0) {
|
||||||
|
try {
|
||||||
|
$this->apiCall('BackupStorages.get', [
|
||||||
|
'id' => $backup
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// not found or other issue, set default
|
||||||
|
$backup = Settings::Get('backup.default_storage');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$access_backups = $this->getBoolParam('access_backups', true, Settings::Get('backup.default_customer_access'));
|
||||||
|
} else {
|
||||||
|
$backup = Settings::Get('backup.default_storage');
|
||||||
|
$access_backups = Settings::Get('backup.default_customer_access');
|
||||||
|
}
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$name = Validate::validate($name, 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
$name = Validate::validate($name, 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$firstname = Validate::validate($firstname, 'first name', Validate::REGEX_DESC_TEXT, '', [], true);
|
$firstname = Validate::validate($firstname, 'first name', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
@@ -400,6 +424,10 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
$allowed_phpconfigs = array_map('intval', $allowed_phpconfigs);
|
$allowed_phpconfigs = array_map('intval', $allowed_phpconfigs);
|
||||||
|
|
||||||
|
if (empty($allowed_phpconfigs) && $phpenabled == 1) {
|
||||||
|
Response::standardError('customerphpenabledbutnoconfig', '', true);
|
||||||
|
}
|
||||||
|
|
||||||
$allowed_mysqlserver = array();
|
$allowed_mysqlserver = array();
|
||||||
if (! empty($p_allowed_mysqlserver) && is_array($p_allowed_mysqlserver)) {
|
if (! empty($p_allowed_mysqlserver) && is_array($p_allowed_mysqlserver)) {
|
||||||
foreach ($p_allowed_mysqlserver as $allowed_ms) {
|
foreach ($p_allowed_mysqlserver as $allowed_ms) {
|
||||||
@@ -534,7 +562,9 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
'theme' => $_theme,
|
'theme' => $_theme,
|
||||||
'custom_notes' => $custom_notes,
|
'custom_notes' => $custom_notes,
|
||||||
'custom_notes_show' => $custom_notes_show,
|
'custom_notes_show' => $custom_notes_show,
|
||||||
'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver)
|
'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver),
|
||||||
|
'backup' => $backup,
|
||||||
|
'access_backups' => $access_backups
|
||||||
];
|
];
|
||||||
|
|
||||||
$ins_stmt = Database::prepare("
|
$ins_stmt = Database::prepare("
|
||||||
@@ -577,7 +607,9 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
`theme` = :theme,
|
`theme` = :theme,
|
||||||
`custom_notes` = :custom_notes,
|
`custom_notes` = :custom_notes,
|
||||||
`custom_notes_show` = :custom_notes_show,
|
`custom_notes_show` = :custom_notes_show,
|
||||||
`allowed_mysqlserver`= :allowed_mysqlserver
|
`allowed_mysqlserver`= :allowed_mysqlserver,
|
||||||
|
`backup` = :backup,
|
||||||
|
`access_backups` = :access_backups
|
||||||
");
|
");
|
||||||
Database::pexecute($ins_stmt, $ins_data, true, true);
|
Database::pexecute($ins_stmt, $ins_data, true, true);
|
||||||
|
|
||||||
@@ -895,7 +927,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
$result['dbspace_used'] = 0;
|
$result['dbspace_used'] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get customer '" . $result['loginname'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get customer '" . $result['loginname'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
||||||
@@ -1025,6 +1057,13 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
* @param array $allowed_mysqlserver
|
* @param array $allowed_mysqlserver
|
||||||
* optional, array of IDs of defined mysql-servers the customer is allowed to use,
|
* optional, array of IDs of defined mysql-servers the customer is allowed to use,
|
||||||
* default is to allow the default dbserver (id=0)
|
* default is to allow the default dbserver (id=0)
|
||||||
|
* @param int $backup
|
||||||
|
* optional, either 0 to disable backup for this customer or a backup-storage-id
|
||||||
|
* where backups are to be stored, requires change_serversettings permissions,
|
||||||
|
* default is system-setting backup.default_storage
|
||||||
|
* @param bool $access_backups
|
||||||
|
* optional, where the customer is allowed to view backups, default is system-setting
|
||||||
|
* default_customer_access
|
||||||
*
|
*
|
||||||
* @access admin, customer
|
* @access admin, customer
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
@@ -1086,6 +1125,24 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
$deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']);
|
$deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']);
|
||||||
$theme = $this->getParam('theme', true, $result['theme']);
|
$theme = $this->getParam('theme', true, $result['theme']);
|
||||||
$allowed_mysqlserver = $this->getParam('allowed_mysqlserver', true, json_decode($result['allowed_mysqlserver'], true));
|
$allowed_mysqlserver = $this->getParam('allowed_mysqlserver', true, json_decode($result['allowed_mysqlserver'], true));
|
||||||
|
|
||||||
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
|
||||||
|
$backup = $this->getParam('backup', true, $result['backup']);
|
||||||
|
if ($backup > 0) {
|
||||||
|
try {
|
||||||
|
$this->apiCall('BackupStorages.get', [
|
||||||
|
'id' => $backup
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// not found or other issue, dont update
|
||||||
|
$backup = $result['backup'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$access_backups = $this->getBoolParam('access_backups', true, Settings::Get('backup.default_customer_access'));
|
||||||
|
} else {
|
||||||
|
$backup = $result['backup'];
|
||||||
|
$access_backups = $result['access_backups'];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// allowed parameters
|
// allowed parameters
|
||||||
$def_language = $this->getParam('def_language', true, $result['def_language']);
|
$def_language = $this->getParam('def_language', true, $result['def_language']);
|
||||||
@@ -1110,6 +1167,9 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
if (!empty($allowed_phpconfigs)) {
|
if (!empty($allowed_phpconfigs)) {
|
||||||
$allowed_phpconfigs = array_map('intval', $allowed_phpconfigs);
|
$allowed_phpconfigs = array_map('intval', $allowed_phpconfigs);
|
||||||
}
|
}
|
||||||
|
if (empty($allowed_phpconfigs) && $phpenabled == 1) {
|
||||||
|
Response::standardError('customerphpenabledbutnoconfig', '', true);
|
||||||
|
}
|
||||||
|
|
||||||
// add permission for allowed mysql usage if customer was not allowed to use mysql prior
|
// add permission for allowed mysql usage if customer was not allowed to use mysql prior
|
||||||
if ($result['mysqls'] == 0 && ($mysqls == -1 || $mysqls > 0)) {
|
if ($result['mysqls'] == 0 && ($mysqls == -1 || $mysqls > 0)) {
|
||||||
@@ -1118,6 +1178,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
if (! empty($allowed_mysqlserver)) {
|
if (! empty($allowed_mysqlserver)) {
|
||||||
$allowed_mysqlserver = array_map('intval', $allowed_mysqlserver);
|
$allowed_mysqlserver = array_map('intval', $allowed_mysqlserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
$def_language = Validate::validate($def_language, 'default language', '', '', [], true);
|
$def_language = Validate::validate($def_language, 'default language', '', '', [], true);
|
||||||
$theme = Validate::validate($theme, 'theme', '', '', [], true);
|
$theme = Validate::validate($theme, 'theme', '', '', [], true);
|
||||||
@@ -1327,7 +1388,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
'vu' => $valid_until
|
'vu' => $valid_until
|
||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1390,7 +1451,9 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
'custom_notes' => $custom_notes,
|
'custom_notes' => $custom_notes,
|
||||||
'custom_notes_show' => $custom_notes_show,
|
'custom_notes_show' => $custom_notes_show,
|
||||||
'api_allowed' => $api_allowed,
|
'api_allowed' => $api_allowed,
|
||||||
'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver)
|
'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver),
|
||||||
|
'backup' => $backup,
|
||||||
|
'access_backups' => $access_backups
|
||||||
];
|
];
|
||||||
$upd_data += $admin_upd_data;
|
$upd_data += $admin_upd_data;
|
||||||
}
|
}
|
||||||
@@ -1433,7 +1496,9 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
`custom_notes` = :custom_notes,
|
`custom_notes` = :custom_notes,
|
||||||
`custom_notes_show` = :custom_notes_show,
|
`custom_notes_show` = :custom_notes_show,
|
||||||
`api_allowed` = :api_allowed,
|
`api_allowed` = :api_allowed,
|
||||||
`allowed_mysqlserver` = :allowed_mysqlserver";
|
`allowed_mysqlserver` = :allowed_mysqlserver,
|
||||||
|
`backup`= :backup,
|
||||||
|
`access_backups` = :access_backups";
|
||||||
$upd_query .= $admin_upd_query;
|
$upd_query .= $admin_upd_query;
|
||||||
}
|
}
|
||||||
$upd_query .= " WHERE `customerid` = :customerid";
|
$upd_query .= " WHERE `customerid` = :customerid";
|
||||||
@@ -1538,7 +1603,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
Database::query($admin_update_query);
|
Database::query($admin_update_query);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited user '" . $result['loginname'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited user '" . $result['loginname'] . "'");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* move customer to another admin/reseller; #1166
|
* move customer to another admin/reseller; #1166
|
||||||
@@ -1911,7 +1976,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
// now, recalculate the resource-usage for the old and the new admin
|
// now, recalculate the resource-usage for the old and the new admin
|
||||||
User::updateCounters(false);
|
User::updateCounters(false);
|
||||||
|
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] moved user '" . $c_result['loginname'] . "' from admin/reseller '" . $c_result['adminname'] . " to admin/reseller '" . $a_result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] moved user '" . $c_result['loginname'] . "' from admin/reseller '" . $c_result['adminname'] . " to admin/reseller '" . $a_result['loginname'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Customers.get', [
|
$result = $this->apiCall('Customers.get', [
|
||||||
'id' => $c_result['customerid']
|
'id' => $c_result['customerid']
|
||||||
|
|||||||
@@ -41,20 +41,22 @@ use PDO;
|
|||||||
/**
|
/**
|
||||||
* @since 0.10.0
|
* @since 0.10.0
|
||||||
*/
|
*/
|
||||||
class CustomerBackups extends ApiCommand implements ResourceEntity
|
class DataDump extends ApiCommand implements ResourceEntity
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add a new customer backup job
|
* add a new data dump job
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* path to store the backup to
|
* path to store the dumped data to
|
||||||
* @param bool $backup_dbs
|
* @param string $pgp_public_key
|
||||||
* optional whether to backup databases, default is 0 (false)
|
* optional pgp public key to encrypt the archive, default is empty
|
||||||
* @param bool $backup_mail
|
* @param bool $dump_dbs
|
||||||
* optional whether to backup mail-data, default is 0 (false)
|
* optional whether to include databases, default is 0 (false)
|
||||||
* @param bool $backup_web
|
* @param bool $dump_mail
|
||||||
* optional whether to backup web-data, default is 0 (false)
|
* optional whether to include mail-data, default is 0 (false)
|
||||||
|
* @param bool $dump_web
|
||||||
|
* optional whether to incoude web-data, default is 0 (false)
|
||||||
* @param int $customerid
|
* @param int $customerid
|
||||||
* optional, required when called as admin (if $loginname is not specified)
|
* optional, required when called as admin (if $loginname is not specified)
|
||||||
* @param string $loginname
|
* @param string $loginname
|
||||||
@@ -72,9 +74,10 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
$path = $this->getParam('path');
|
$path = $this->getParam('path');
|
||||||
|
|
||||||
// parameter
|
// parameter
|
||||||
$backup_dbs = $this->getBoolParam('backup_dbs', true, 0);
|
$pgp_public_key = $this->getParam('pgp_public_key', true, '');
|
||||||
$backup_mail = $this->getBoolParam('backup_mail', true, 0);
|
$dump_dbs = $this->getBoolParam('dump_dbs', true, 0);
|
||||||
$backup_web = $this->getBoolParam('backup_web', true, 0);
|
$dump_mail = $this->getBoolParam('dump_mail', true, 0);
|
||||||
|
$dump_web = $this->getBoolParam('dump_web', true, 0);
|
||||||
|
|
||||||
// get customer data
|
// get customer data
|
||||||
$customer = $this->getCustomerData();
|
$customer = $this->getCustomerData();
|
||||||
@@ -86,19 +89,32 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// path cannot be the customers docroot
|
// path cannot be the customers docroot
|
||||||
if ($path == FileDir::makeCorrectDir($customer['documentroot'])) {
|
if ($path == FileDir::makeCorrectDir($customer['documentroot'])) {
|
||||||
Response::standardError('backupfoldercannotbedocroot', '', true);
|
Response::standardError('dumpfoldercannotbedocroot', '', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($backup_dbs != '1') {
|
// pgp public key validation
|
||||||
$backup_dbs = '0';
|
if (!empty($pgp_public_key)) {
|
||||||
|
// check if gnupg extension is loaded
|
||||||
|
if (!extension_loaded('gnupg')) {
|
||||||
|
Response::standardError('gnupgextensionnotavailable', '', true);
|
||||||
|
}
|
||||||
|
// check if the pgp public key is a valid key
|
||||||
|
putenv('GNUPGHOME='.sys_get_temp_dir());
|
||||||
|
if (gnupg_import(gnupg_init(), $pgp_public_key) === false) {
|
||||||
|
Response::standardError('invalidpgppublickey', '', true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($backup_mail != '1') {
|
if ($dump_dbs != '1') {
|
||||||
$backup_mail = '0';
|
$dump_dbs = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($backup_web != '1') {
|
if ($dump_mail != '1') {
|
||||||
$backup_web = '0';
|
$dump_mail = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dump_web != '1') {
|
||||||
|
$dump_web = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
$task_data = [
|
$task_data = [
|
||||||
@@ -107,61 +123,63 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
'gid' => $customer['guid'],
|
'gid' => $customer['guid'],
|
||||||
'loginname' => $customer['loginname'],
|
'loginname' => $customer['loginname'],
|
||||||
'destdir' => $path,
|
'destdir' => $path,
|
||||||
'backup_dbs' => $backup_dbs,
|
'pgp_public_key' => $pgp_public_key,
|
||||||
'backup_mail' => $backup_mail,
|
'dump_dbs' => $dump_dbs,
|
||||||
'backup_web' => $backup_web
|
'dump_mail' => $dump_mail,
|
||||||
|
'dump_web' => $dump_web
|
||||||
];
|
];
|
||||||
// schedule backup job
|
|
||||||
Cronjob::inserttask(TaskId::CREATE_CUSTOMER_BACKUP, $task_data);
|
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added customer-backup job for '" . $customer['loginname'] . "'. Target directory: " . $userpath);
|
// schedule export job
|
||||||
|
Cronjob::inserttask(TaskId::CREATE_CUSTOMER_DATADUMP, $task_data);
|
||||||
|
|
||||||
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added customer data export job for '" . $customer['loginname'] . "'. Target directory: " . $userpath);
|
||||||
return $this->response($task_data);
|
return $this->response($task_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check whether backup is enabled systemwide and if accessible for customer (hide_options)
|
* check whether data dump is enabled systemwide and if accessible for customer (hide_options)
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private function validateAccess()
|
private function validateAccess()
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.backupenabled') != 1) {
|
if (Settings::Get('system.exportenabled') != 1) {
|
||||||
throw new Exception("You cannot access this resource", 405);
|
throw new Exception("You cannot access this resource", 405);
|
||||||
}
|
}
|
||||||
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras')) {
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras')) {
|
||||||
throw new Exception("You cannot access this resource", 405);
|
throw new Exception("You cannot access this resource", 405);
|
||||||
}
|
}
|
||||||
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras.backup')) {
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras.export')) {
|
||||||
throw new Exception("You cannot access this resource", 405);
|
throw new Exception("You cannot access this resource", 405);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You cannot get a planned backup.
|
* You cannot get a planned data export.
|
||||||
* Try CustomerBackups.listing()
|
* Try DataDump.listing()
|
||||||
*/
|
*/
|
||||||
public function get()
|
public function get()
|
||||||
{
|
{
|
||||||
throw new Exception('You cannot get a planned backup. Try CustomerBackups.listing()', 303);
|
throw new Exception('You cannot get a planned data export. Try DataDump.listing()', 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You cannot update a planned backup.
|
* You cannot update a planned data export.
|
||||||
* You need to delete it and re-add it.
|
* You need to delete it and re-add it.
|
||||||
*/
|
*/
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
throw new Exception('You cannot update a planned backup. You need to delete it and re-add it.', 303);
|
throw new Exception('You cannot update a planned data export. You need to delete it and re-add it.', 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* list all planned backup-jobs, if called from an admin, list all planned backup-jobs of all customers you are
|
* list all planned data export jobs, if called from an admin, list all planned data export jobs of all customers you are
|
||||||
* allowed to view, or specify id or loginname for one specific customer
|
* allowed to view, or specify id or loginname for one specific customer
|
||||||
*
|
*
|
||||||
* @param int $customerid
|
* @param int $customerid
|
||||||
* optional, admin-only, select backup-jobs of a specific customer by id
|
* optional, admin-only, select data export jobs of a specific customer by id
|
||||||
* @param string $loginname
|
* @param string $loginname
|
||||||
* optional, admin-only, select backup-jobs of a specific customer by loginname
|
* optional, admin-only, select data export jobs of a specific customer by loginname
|
||||||
* @param array $sql_search
|
* @param array $sql_search
|
||||||
* optional array with index = fieldname, and value = array with 'op' => operator (one of <, > or =),
|
* optional array with index = fieldname, and value = array with 'op' => operator (one of <, > or =),
|
||||||
* LIKE is used if left empty and 'value' => searchvalue
|
* LIKE is used if left empty and 'value' => searchvalue
|
||||||
@@ -181,9 +199,9 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
{
|
{
|
||||||
$this->validateAccess();
|
$this->validateAccess();
|
||||||
|
|
||||||
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
|
$customer_ids = $this->getAllowedCustomerIds('extras.export');
|
||||||
|
|
||||||
// check whether there is a backup-job for this customer
|
// check whether there is a data export job for this customer
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
|
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
|
||||||
Database::pexecute($sel_stmt, $query_fields, true, true);
|
Database::pexecute($sel_stmt, $query_fields, true, true);
|
||||||
@@ -194,7 +212,7 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
$result[] = $entry;
|
$result[] = $entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list customer-backups");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list customer data dump jobs");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -202,12 +220,12 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the total number of planned backups
|
* returns the total number of planned data exports
|
||||||
*
|
*
|
||||||
* @param int $customerid
|
* @param int $customerid
|
||||||
* optional, admin-only, select backup-jobs of a specific customer by id
|
* optional, admin-only, select data export jobs of a specific customer by id
|
||||||
* @param string $loginname
|
* @param string $loginname
|
||||||
* optional, admin-only, select backup-jobs of a specific customer by loginname
|
* optional, admin-only, select data export jobs of a specific customer by loginname
|
||||||
*
|
*
|
||||||
* @access admin, customer
|
* @access admin, customer
|
||||||
* @return string json-encoded response message
|
* @return string json-encoded response message
|
||||||
@@ -217,9 +235,9 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
{
|
{
|
||||||
$this->validateAccess();
|
$this->validateAccess();
|
||||||
|
|
||||||
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
|
$customer_ids = $this->getAllowedCustomerIds('extras.export');
|
||||||
|
|
||||||
// check whether there is a backup-job for this customer
|
// check whether there is a data export job for this customer
|
||||||
$result_count = 0;
|
$result_count = 0;
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'");
|
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'");
|
||||||
Database::pexecute($sel_stmt, null, true, true);
|
Database::pexecute($sel_stmt, null, true, true);
|
||||||
@@ -233,10 +251,10 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* delete a planned backup-jobs by id, if called from an admin you need to specify the customerid/loginname
|
* delete a planned data export jobs by id, if called from an admin you need to specify the customerid/loginname
|
||||||
*
|
*
|
||||||
* @param int $backup_job_entry
|
* @param int $job_entry
|
||||||
* id of backup job
|
* id of data export job
|
||||||
* @param int $customerid
|
* @param int $customerid
|
||||||
* optional, required when called as admin (if $loginname is not specified)
|
* optional, required when called as admin (if $loginname is not specified)
|
||||||
* @param string $loginname
|
* @param string $loginname
|
||||||
@@ -248,26 +266,26 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
*/
|
*/
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
// get planned backups
|
// get planned exports
|
||||||
$result = $this->apiCall('CustomerBackups.listing', $this->getParamList());
|
$result = $this->apiCall('DataDump.listing', $this->getParamList());
|
||||||
|
|
||||||
$entry = $this->getParam('backup_job_entry');
|
$entry = $this->getParam('job_entry');
|
||||||
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
|
$customer_ids = $this->getAllowedCustomerIds('extras.export');
|
||||||
|
|
||||||
if ($result['count'] > 0 && $entry > 0) {
|
if ($result['count'] > 0 && $entry > 0) {
|
||||||
// prepare statement
|
// prepare statement
|
||||||
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :tid");
|
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :tid");
|
||||||
// check for the correct job
|
// check for the correct job
|
||||||
foreach ($result['list'] as $backupjob) {
|
foreach ($result['list'] as $exportjob) {
|
||||||
if ($backupjob['id'] == $entry && in_array($backupjob['data']['customerid'], $customer_ids)) {
|
if ($exportjob['id'] == $entry && in_array($exportjob['data']['customerid'], $customer_ids)) {
|
||||||
Database::pexecute($del_stmt, [
|
Database::pexecute($del_stmt, [
|
||||||
'tid' => $entry
|
'tid' => $entry
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted planned customer-backup #" . $entry);
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted planned customer data export job #" . $entry);
|
||||||
return $this->response(true);
|
return $this->response(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Exception('Backup job with id #' . $entry . ' could not be found', 404);
|
throw new Exception('Data export job with id #' . $entry . ' could not be found', 404);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$id = Database::lastInsertId();
|
$id = Database::lastInsertId();
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-option for '" . $userpath . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added directory-option for '" . $userpath . "'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
|
||||||
$result = $this->apiCall('DirOptions.get', [
|
$result = $this->apiCall('DirOptions.get', [
|
||||||
@@ -247,7 +247,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
$params['id'] = $id;
|
$params['id'] = $id;
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory options for '" . $result['path'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get directory options for '" . $result['path'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = "id #" . $id;
|
$key = "id #" . $id;
|
||||||
@@ -331,7 +331,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id
|
"id" => $id
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited directory options for '" . str_replace($customer['documentroot'], '/', $result['path']) . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited directory options for '" . str_replace($customer['documentroot'], '/', $result['path']) . "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->apiCall('DirOptions.get', [
|
$result = $this->apiCall('DirOptions.get', [
|
||||||
@@ -379,7 +379,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-options");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list directory-options");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -478,7 +478,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
"customerid" => $customer_data['customerid'],
|
"customerid" => $customer_data['customerid'],
|
||||||
"id" => $id
|
"id" => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$id = Database::lastInsertId();
|
$id = Database::lastInsertId();
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-protection for '" . $username . " (" . $path . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added directory-protection for '" . $username . " (" . $path . ")'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
|
||||||
$result = $this->apiCall('DirProtections.get', [
|
$result = $this->apiCall('DirProtections.get', [
|
||||||
@@ -196,7 +196,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
$params['idun'] = ($id <= 0 ? $username : $id);
|
$params['idun'] = ($id <= 0 ? $username : $id);
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory protection for '" . $result['path'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get directory protection for '" . $result['path'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
||||||
@@ -279,7 +279,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'");
|
||||||
$result = $this->apiCall('DirProtections.get', [
|
$result = $this->apiCall('DirProtections.get', [
|
||||||
'id' => $result['id']
|
'id' => $result['id']
|
||||||
]);
|
]);
|
||||||
@@ -325,7 +325,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-protections");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list directory-protections");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -413,7 +413,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id
|
"id" => $id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -302,6 +302,8 @@ class DomainZones extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
} elseif ($type == 'SSHFP' && !empty($content)) {
|
} elseif ($type == 'SSHFP' && !empty($content)) {
|
||||||
$content = $content;
|
$content = $content;
|
||||||
|
} elseif ($type == 'TLSA' && !empty($content)) {
|
||||||
|
$content = $content;
|
||||||
} elseif ($type == 'TXT' && !empty($content)) {
|
} elseif ($type == 'TXT' && !empty($content)) {
|
||||||
// check that TXT content is enclosed in " "
|
// check that TXT content is enclosed in " "
|
||||||
$content = Dns::encloseTXTContent($content);
|
$content = Dns::encloseTXTContent($content);
|
||||||
@@ -413,7 +415,7 @@ class DomainZones extends ApiCommand implements ResourceEntity
|
|||||||
$zone = Dns::createDomainZone($id);
|
$zone = Dns::createDomainZone($id);
|
||||||
$zonefile = (string)$zone;
|
$zonefile = (string)$zone;
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get dns-zone for '" . $result['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get dns-zone for '" . $result['domain'] . "'");
|
||||||
return $this->response(explode("\n", $zonefile));
|
return $this->response(explode("\n", $zonefile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT
|
SELECT
|
||||||
`d`.*, `c`.`loginname`, `c`.`deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`, `c`.`adminid` as customeradmin,
|
`d`.*, `c`.`loginname`, `c`.`deactivated` as `customer_deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`, `c`.`adminid` as customeradmin,
|
||||||
`ad`.`id` AS `aliasdomainid`, `ad`.`domain` AS `aliasdomain`
|
`ad`.`id` AS `aliasdomainid`, `ad`.`domain` AS `aliasdomain`
|
||||||
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
||||||
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
|
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
|
||||||
@@ -110,7 +110,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
*
|
*
|
||||||
* @param number $domain_id
|
* @param number $domain_id
|
||||||
* @param bool $ssl_only
|
* @param bool $ssl_only
|
||||||
* optional, return only ssl enabled ip's, default false
|
* optional, return only ssl enabled ips, default false
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function getIpsForDomain($domain_id = 0, $ssl_only = false)
|
private function getIpsForDomain($domain_id = 0, $ssl_only = false)
|
||||||
@@ -190,9 +190,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, whether to create an exclusive web-logfile for this domain, default 0 (false)
|
* optional, whether to create an exclusive web-logfile for this domain, default 0 (false)
|
||||||
* @param int $alias
|
* @param int $alias
|
||||||
* optional, domain-id of a domain that the new domain should be an alias of, default 0 (none)
|
* optional, domain-id of a domain that the new domain should be an alias of, default 0 (none)
|
||||||
* @param int $issubof
|
|
||||||
* optional, domain-id of a domain this domain is a subdomain of (required for webserver-cronjob to
|
|
||||||
* generate the correct order), default 0 (none)
|
|
||||||
* @param string $registration_date
|
* @param string $registration_date
|
||||||
* optional, date of domain registration in form of YYYY-MM-DD, default empty (none)
|
* optional, date of domain registration in form of YYYY-MM-DD, default empty (none)
|
||||||
* @param string $termination_date
|
* @param string $termination_date
|
||||||
@@ -210,7 +207,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* @param string $ssl_specialsettings
|
* @param string $ssl_specialsettings
|
||||||
* optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty
|
* optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty
|
||||||
* @param bool $include_specialsettings
|
* @param bool $include_specialsettings
|
||||||
* optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false
|
* optional, whether to include non-ssl specialsettings in the generated ssl-vhost, default false
|
||||||
* @param bool $notryfiles
|
* @param bool $notryfiles
|
||||||
* optional, [nginx only] do not generate the default try-files directive, default 0 (false)
|
* optional, [nginx only] do not generate the default try-files directive, default 0 (false)
|
||||||
* @param bool $writeaccesslog
|
* @param bool $writeaccesslog
|
||||||
@@ -219,12 +216,14 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, Enable writing an error-log file for this domain, default 1 (true)
|
* optional, Enable writing an error-log file for this domain, default 1 (true)
|
||||||
* @param string $documentroot
|
* @param string $documentroot
|
||||||
* optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be
|
* optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be
|
||||||
* aware, if path starts with / it it considered a full path, not relative to customer-docroot. Also
|
* aware, if path starts with / it is considered a full path, not relative to customer-docroot. Also
|
||||||
* specifying a URL is possible here (redirect), default empty (autogenerated)
|
* specifying a URL is possible here (redirect), default empty (autogenerated)
|
||||||
* @param bool $phpenabled
|
* @param bool $phpenabled
|
||||||
* optional, whether php is enabled for this domain, default 0 (false)
|
* optional, whether php is enabled for this domain, default 0 (false)
|
||||||
* @param bool $openbasedir
|
* @param bool $openbasedir
|
||||||
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
||||||
|
* @param int $openbasedir_path
|
||||||
|
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
||||||
* @param int $mod_fcgid_starter
|
* @param int $mod_fcgid_starter
|
||||||
@@ -242,7 +241,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, do NOT set the systems default ssl ip addresses if none are given via $ssl_ipandport
|
* optional, do NOT set the systems default ssl ip addresses if none are given via $ssl_ipandport
|
||||||
* parameter
|
* parameter
|
||||||
* @param bool $sslenabled
|
* @param bool $sslenabled
|
||||||
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
* optional, whether SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
||||||
* 1 (true)
|
* 1 (true)
|
||||||
* @param bool $http2
|
* @param bool $http2
|
||||||
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
|
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
|
||||||
@@ -250,9 +249,9 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* @param int $hsts_maxage
|
* @param int $hsts_maxage
|
||||||
* optional max-age value for HSTS header
|
* optional max-age value for HSTS header
|
||||||
* @param bool $hsts_sub
|
* @param bool $hsts_sub
|
||||||
* optional whether or not to add subdomains to the HSTS header
|
* optional whether to add subdomains to the HSTS header
|
||||||
* @param bool $hsts_preload
|
* @param bool $hsts_preload
|
||||||
* optional whether or not to preload HSTS header value
|
* optional whether to preload HSTS header value
|
||||||
* @param bool $ocsp_stapling
|
* @param bool $ocsp_stapling
|
||||||
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
|
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
|
||||||
* @param bool $honorcipherorder
|
* @param bool $honorcipherorder
|
||||||
@@ -261,7 +260,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional whether to enable or disable TLS sessiontickets (RFC 5077) for this domain. default 1
|
* optional whether to enable or disable TLS sessiontickets (RFC 5077) for this domain. default 1
|
||||||
* (true), requires SSL
|
* (true), requires SSL
|
||||||
* @param bool $override_tls
|
* @param bool $override_tls
|
||||||
* optional whether or not to override system-tls settings like protocol, ssl-ciphers and if applicable
|
* optional whether to override system-tls settings like protocol, ssl-ciphers and if applicable
|
||||||
* tls-1.3 ciphers, requires change_serversettings flag for the admin, default false
|
* tls-1.3 ciphers, requires change_serversettings flag for the admin, default false
|
||||||
* @param array $ssl_protocols
|
* @param array $ssl_protocols
|
||||||
* optional list of allowed/used ssl/tls protocols, see system.ssl_protocols setting, only used/required
|
* optional list of allowed/used ssl/tls protocols, see system.ssl_protocols setting, only used/required
|
||||||
@@ -296,7 +295,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$serveraliasoption = $this->getParam('selectserveralias', true, Settings::Get('system.domaindefaultalias'));
|
$serveraliasoption = $this->getParam('selectserveralias', true, Settings::Get('system.domaindefaultalias'));
|
||||||
$speciallogfile = $this->getBoolParam('speciallogfile', true, 0);
|
$speciallogfile = $this->getBoolParam('speciallogfile', true, 0);
|
||||||
$aliasdomain = intval($this->getParam('alias', true, 0));
|
$aliasdomain = intval($this->getParam('alias', true, 0));
|
||||||
$issubof = $this->getParam('issubof', true, 0);
|
|
||||||
$registration_date = $this->getParam('registration_date', true, '');
|
$registration_date = $this->getParam('registration_date', true, '');
|
||||||
$termination_date = $this->getParam('termination_date', true, '');
|
$termination_date = $this->getParam('termination_date', true, '');
|
||||||
$caneditdomain = $this->getBoolParam('caneditdomain', true, 0);
|
$caneditdomain = $this->getBoolParam('caneditdomain', true, 0);
|
||||||
@@ -312,6 +310,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$documentroot = $this->getParam('documentroot', true, '');
|
$documentroot = $this->getParam('documentroot', true, '');
|
||||||
$phpenabled = $this->getBoolParam('phpenabled', true, 0);
|
$phpenabled = $this->getBoolParam('phpenabled', true, 0);
|
||||||
$openbasedir = $this->getBoolParam('openbasedir', true, 0);
|
$openbasedir = $this->getBoolParam('openbasedir', true, 0);
|
||||||
|
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, 1);
|
$phpsettingid = $this->getParam('phpsettingid', true, 1);
|
||||||
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, -1);
|
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, -1);
|
||||||
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
|
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
|
||||||
@@ -530,6 +529,10 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$mod_fcgid_maxrequests = '-1';
|
$mod_fcgid_maxrequests = '-1';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
|
||||||
|
$openbasedir_path = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check non-ssl IP
|
// check non-ssl IP
|
||||||
$ipandports = $this->validateIpAddresses($p_ipandports);
|
$ipandports = $this->validateIpAddresses($p_ipandports);
|
||||||
// check ssl IP
|
// check ssl IP
|
||||||
@@ -658,10 +661,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$serveraliasoption = '0';
|
$serveraliasoption = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($issubof <= 0) {
|
|
||||||
$issubof = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
if ($domain == '') {
|
if ($domain == '') {
|
||||||
Response::standardError([
|
Response::standardError([
|
||||||
@@ -701,6 +700,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
'caneditdomain' => $caneditdomain,
|
'caneditdomain' => $caneditdomain,
|
||||||
'phpenabled' => $phpenabled,
|
'phpenabled' => $phpenabled,
|
||||||
'openbasedir' => $openbasedir,
|
'openbasedir' => $openbasedir,
|
||||||
|
'openbasedir_path' => $openbasedir_path,
|
||||||
'speciallogfile' => $speciallogfile,
|
'speciallogfile' => $speciallogfile,
|
||||||
'specialsettings' => $specialsettings,
|
'specialsettings' => $specialsettings,
|
||||||
'ssl_specialsettings' => $ssl_specialsettings,
|
'ssl_specialsettings' => $ssl_specialsettings,
|
||||||
@@ -715,7 +715,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
'phpsettingid' => $phpsettingid,
|
'phpsettingid' => $phpsettingid,
|
||||||
'mod_fcgid_starter' => $mod_fcgid_starter,
|
'mod_fcgid_starter' => $mod_fcgid_starter,
|
||||||
'mod_fcgid_maxrequests' => $mod_fcgid_maxrequests,
|
'mod_fcgid_maxrequests' => $mod_fcgid_maxrequests,
|
||||||
'ismainbutsubto' => $issubof,
|
|
||||||
'letsencrypt' => $letsencrypt,
|
'letsencrypt' => $letsencrypt,
|
||||||
'http2' => $http2,
|
'http2' => $http2,
|
||||||
'hsts' => $hsts_maxage,
|
'hsts' => $hsts_maxage,
|
||||||
@@ -754,6 +753,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`caneditdomain` = :caneditdomain,
|
`caneditdomain` = :caneditdomain,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`speciallogfile` = :speciallogfile,
|
`speciallogfile` = :speciallogfile,
|
||||||
`specialsettings` = :specialsettings,
|
`specialsettings` = :specialsettings,
|
||||||
`ssl_specialsettings` = :ssl_specialsettings,
|
`ssl_specialsettings` = :ssl_specialsettings,
|
||||||
@@ -768,7 +768,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`phpsettingid` = :phpsettingid,
|
`phpsettingid` = :phpsettingid,
|
||||||
`mod_fcgid_starter` = :mod_fcgid_starter,
|
`mod_fcgid_starter` = :mod_fcgid_starter,
|
||||||
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
||||||
`ismainbutsubto` = :ismainbutsubto,
|
|
||||||
`letsencrypt` = :letsencrypt,
|
`letsencrypt` = :letsencrypt,
|
||||||
`http2` = :http2,
|
`http2` = :http2,
|
||||||
`hsts` = :hsts,
|
`hsts` = :hsts,
|
||||||
@@ -889,7 +888,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
||||||
}
|
}
|
||||||
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get domain '" . $result['domain'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get domain '" . $result['domain'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
||||||
@@ -1060,9 +1059,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* default 0 (false)
|
* default 0 (false)
|
||||||
* @param int $alias
|
* @param int $alias
|
||||||
* optional, domain-id of a domain that the new domain should be an alias of, default 0 (none)
|
* optional, domain-id of a domain that the new domain should be an alias of, default 0 (none)
|
||||||
* @param int $issubof
|
|
||||||
* optional, domain-id of a domain this domain is a subdomain of (required for webserver-cronjob to
|
|
||||||
* generate the correct order), default 0 (none)
|
|
||||||
* @param string $registration_date
|
* @param string $registration_date
|
||||||
* optional, date of domain registration in form of YYYY-MM-DD, default empty (none)
|
* optional, date of domain registration in form of YYYY-MM-DD, default empty (none)
|
||||||
* @param string $termination_date
|
* @param string $termination_date
|
||||||
@@ -1080,7 +1076,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* @param string $ssl_specialsettings
|
* @param string $ssl_specialsettings
|
||||||
* optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty
|
* optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty
|
||||||
* @param bool $include_specialsettings
|
* @param bool $include_specialsettings
|
||||||
* optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false
|
* optional, whether to include non-ssl specialsettings in the generated ssl-vhost, default false
|
||||||
* @param bool $specialsettingsforsubdomains
|
* @param bool $specialsettingsforsubdomains
|
||||||
* optional, whether to apply specialsettings to all subdomains of this domain, default is read from
|
* optional, whether to apply specialsettings to all subdomains of this domain, default is read from
|
||||||
* setting system.apply_specialsettings_default
|
* setting system.apply_specialsettings_default
|
||||||
@@ -1092,7 +1088,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, Enable writing an error-log file for this domain, default 1 (true)
|
* optional, Enable writing an error-log file for this domain, default 1 (true)
|
||||||
* @param string $documentroot
|
* @param string $documentroot
|
||||||
* optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be
|
* optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be
|
||||||
* aware, if path starts with / it it considered a full path, not relative to customer-docroot. Also
|
* aware, if path starts with / it is considered a full path, not relative to customer-docroot. Also
|
||||||
* specifying a URL is possible here (redirect), default empty (autogenerated)
|
* specifying a URL is possible here (redirect), default empty (autogenerated)
|
||||||
* @param bool $phpenabled
|
* @param bool $phpenabled
|
||||||
* optional, whether php is enabled for this domain, default 0 (false)
|
* optional, whether php is enabled for this domain, default 0 (false)
|
||||||
@@ -1101,6 +1097,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* from setting system.apply_phpconfigs_default
|
* from setting system.apply_phpconfigs_default
|
||||||
* @param bool $openbasedir
|
* @param bool $openbasedir
|
||||||
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
||||||
|
* @param int $openbasedir_path
|
||||||
|
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
||||||
* @param int $mod_fcgid_starter
|
* @param int $mod_fcgid_starter
|
||||||
@@ -1119,7 +1117,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, if set to true and no $ssl_ipandport value is given, the ip's get removed, otherwise, the
|
* optional, if set to true and no $ssl_ipandport value is given, the ip's get removed, otherwise, the
|
||||||
* currently set value is used, default false
|
* currently set value is used, default false
|
||||||
* @param bool $sslenabled
|
* @param bool $sslenabled
|
||||||
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
* optional, whether SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
||||||
* 1 (true)
|
* 1 (true)
|
||||||
* @param bool $http2
|
* @param bool $http2
|
||||||
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
|
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
|
||||||
@@ -1127,9 +1125,9 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* @param int $hsts_maxage
|
* @param int $hsts_maxage
|
||||||
* optional max-age value for HSTS header
|
* optional max-age value for HSTS header
|
||||||
* @param bool $hsts_sub
|
* @param bool $hsts_sub
|
||||||
* optional whether or not to add subdomains to the HSTS header
|
* optional whether to add subdomains to the HSTS header
|
||||||
* @param bool $hsts_preload
|
* @param bool $hsts_preload
|
||||||
* optional whether or not to preload HSTS header value
|
* optional whether to preload HSTS header value
|
||||||
* @param bool $ocsp_stapling
|
* @param bool $ocsp_stapling
|
||||||
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
|
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
|
||||||
* @param bool $honorcipherorder
|
* @param bool $honorcipherorder
|
||||||
@@ -1139,6 +1137,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* (true), requires SSL
|
* (true), requires SSL
|
||||||
* @param string $description
|
* @param string $description
|
||||||
* optional custom description (currently not used/shown in the frontend), default empty
|
* optional custom description (currently not used/shown in the frontend), default empty
|
||||||
|
* @param bool $deactivated
|
||||||
|
* optional, if 1 (true) the domain can be deactivated/suspended
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
@@ -1180,7 +1180,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$speciallogfile = $this->getBoolParam('speciallogfile', true, $result['speciallogfile']);
|
$speciallogfile = $this->getBoolParam('speciallogfile', true, $result['speciallogfile']);
|
||||||
$speciallogverified = $this->getBoolParam('speciallogverified', true, 0);
|
$speciallogverified = $this->getBoolParam('speciallogverified', true, 0);
|
||||||
$aliasdomain = intval($this->getParam('alias', true, $result['aliasdomain']));
|
$aliasdomain = intval($this->getParam('alias', true, $result['aliasdomain']));
|
||||||
$issubof = $this->getParam('issubof', true, $result['ismainbutsubto']);
|
|
||||||
$registration_date = $this->getParam('registration_date', true, $result['registration_date']);
|
$registration_date = $this->getParam('registration_date', true, $result['registration_date']);
|
||||||
$termination_date = $this->getParam('termination_date', true, $result['termination_date']);
|
$termination_date = $this->getParam('termination_date', true, $result['termination_date']);
|
||||||
$caneditdomain = $this->getBoolParam('caneditdomain', true, $result['caneditdomain']);
|
$caneditdomain = $this->getBoolParam('caneditdomain', true, $result['caneditdomain']);
|
||||||
@@ -1198,6 +1197,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$phpenabled = $this->getBoolParam('phpenabled', true, $result['phpenabled']);
|
$phpenabled = $this->getBoolParam('phpenabled', true, $result['phpenabled']);
|
||||||
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, Settings::Get('system.apply_phpconfigs_default'));
|
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, Settings::Get('system.apply_phpconfigs_default'));
|
||||||
$openbasedir = $this->getBoolParam('openbasedir', true, $result['openbasedir']);
|
$openbasedir = $this->getBoolParam('openbasedir', true, $result['openbasedir']);
|
||||||
|
$openbasedir_path = $this->getParam('openbasedir_path', true, $result['openbasedir_path']);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
||||||
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, $result['mod_fcgid_starter']);
|
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, $result['mod_fcgid_starter']);
|
||||||
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, $result['mod_fcgid_maxrequests']);
|
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, $result['mod_fcgid_maxrequests']);
|
||||||
@@ -1234,6 +1234,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$tlsv13_cipher_list = $result['tlsv13_cipher_list'];
|
$tlsv13_cipher_list = $result['tlsv13_cipher_list'];
|
||||||
}
|
}
|
||||||
$description = $this->getParam('description', true, $result['description']);
|
$description = $this->getParam('description', true, $result['description']);
|
||||||
|
$deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']);
|
||||||
|
|
||||||
// count subdomain usage of source-domain
|
// count subdomain usage of source-domain
|
||||||
$subdomains_stmt = Database::prepare("
|
$subdomains_stmt = Database::prepare("
|
||||||
@@ -1489,6 +1490,11 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$mod_fcgid_maxrequests = $result['mod_fcgid_maxrequests'];
|
$mod_fcgid_maxrequests = $result['mod_fcgid_maxrequests'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check changes of openbasedir-path variable
|
||||||
|
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
|
||||||
|
$openbasedir_path = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check non-ssl IP
|
// check non-ssl IP
|
||||||
$ipandports = $this->validateIpAddresses($p_ipandports, false, $result['id']);
|
$ipandports = $this->validateIpAddresses($p_ipandports, false, $result['id']);
|
||||||
// check ssl IP
|
// check ssl IP
|
||||||
@@ -1623,10 +1629,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
Response::standardError('domainisaliasorothercustomer', '', true);
|
Response::standardError('domainisaliasorothercustomer', '', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($issubof <= 0) {
|
|
||||||
$issubof = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($serveraliasoption != '1' && $serveraliasoption != '2') {
|
if ($serveraliasoption != '1' && $serveraliasoption != '2') {
|
||||||
$serveraliasoption = '0';
|
$serveraliasoption = '0';
|
||||||
}
|
}
|
||||||
@@ -1634,7 +1636,30 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
||||||
$iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0';
|
$iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0';
|
||||||
|
|
||||||
if ($documentroot != $result['documentroot'] || $ssl_redirect != $result['ssl_redirect'] || $wwwserveralias != $result['wwwserveralias'] || $iswildcarddomain != $result['iswildcarddomain'] || $phpenabled != $result['phpenabled'] || $openbasedir != $result['openbasedir'] || $phpsettingid != $result['phpsettingid'] || $mod_fcgid_starter != $result['mod_fcgid_starter'] || $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests'] || $specialsettings != $result['specialsettings'] || $ssl_specialsettings != $result['ssl_specialsettings'] || $notryfiles != $result['notryfiles'] || $writeaccesslog != $result['writeaccesslog'] || $writeerrorlog != $result['writeerrorlog'] || $aliasdomain != $result['aliasdomain'] || $issubof != $result['ismainbutsubto'] || $email_only != $result['email_only'] || ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1') || $letsencrypt != $result['letsencrypt'] || $http2 != $result['http2'] || $hsts_maxage != $result['hsts'] || $hsts_sub != $result['hsts_sub'] || $hsts_preload != $result['hsts_preload'] || $ocsp_stapling != $result['ocsp_stapling']) {
|
if ($documentroot != $result['documentroot']
|
||||||
|
|| $ssl_redirect != $result['ssl_redirect']
|
||||||
|
|| $wwwserveralias != $result['wwwserveralias']
|
||||||
|
|| $iswildcarddomain != $result['iswildcarddomain']
|
||||||
|
|| $phpenabled != $result['phpenabled']
|
||||||
|
|| $openbasedir != $result['openbasedir']
|
||||||
|
|| $phpsettingid != $result['phpsettingid']
|
||||||
|
|| $mod_fcgid_starter != $result['mod_fcgid_starter']
|
||||||
|
|| $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests']
|
||||||
|
|| $specialsettings != $result['specialsettings']
|
||||||
|
|| $ssl_specialsettings != $result['ssl_specialsettings']
|
||||||
|
|| $notryfiles != $result['notryfiles']
|
||||||
|
|| $writeaccesslog != $result['writeaccesslog']
|
||||||
|
|| $writeerrorlog != $result['writeerrorlog']
|
||||||
|
|| $aliasdomain != $result['aliasdomain']
|
||||||
|
|| $email_only != $result['email_only']
|
||||||
|
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|
||||||
|
|| $letsencrypt != $result['letsencrypt']
|
||||||
|
|| $http2 != $result['http2']
|
||||||
|
|| $hsts_maxage != $result['hsts']
|
||||||
|
|| $hsts_sub != $result['hsts_sub']
|
||||||
|
|| $hsts_preload != $result['hsts_preload']
|
||||||
|
|| $ocsp_stapling != $result['ocsp_stapling']
|
||||||
|
) {
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1760,7 +1785,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
Database::pexecute($upd_stmt, [
|
Database::pexecute($upd_stmt, [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] removed specialsettings on all subdomains of domain #" . $id);
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] removed specialsettings on all subdomains of domain #" . $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
||||||
@@ -1782,7 +1807,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$update_data['wwwserveralias'] = $wwwserveralias;
|
$update_data['wwwserveralias'] = $wwwserveralias;
|
||||||
$update_data['iswildcarddomain'] = $iswildcarddomain;
|
$update_data['iswildcarddomain'] = $iswildcarddomain;
|
||||||
$update_data['phpenabled'] = $phpenabled;
|
$update_data['phpenabled'] = $phpenabled;
|
||||||
$update_data['openbasedir'] = $openbasedir;
|
$update_data['openbasedir'] = $openbasedir;;
|
||||||
|
$update_data['openbasedir_path'] = $openbasedir_path;
|
||||||
$update_data['speciallogfile'] = $speciallogfile;
|
$update_data['speciallogfile'] = $speciallogfile;
|
||||||
$update_data['phpsettingid'] = $phpsettingid;
|
$update_data['phpsettingid'] = $phpsettingid;
|
||||||
$update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
$update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
||||||
@@ -1795,7 +1821,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$update_data['writeerrorlog'] = $writeerrorlog;
|
$update_data['writeerrorlog'] = $writeerrorlog;
|
||||||
$update_data['registration_date'] = $registration_date;
|
$update_data['registration_date'] = $registration_date;
|
||||||
$update_data['termination_date'] = $termination_date;
|
$update_data['termination_date'] = $termination_date;
|
||||||
$update_data['ismainbutsubto'] = $issubof;
|
|
||||||
$update_data['letsencrypt'] = $letsencrypt;
|
$update_data['letsencrypt'] = $letsencrypt;
|
||||||
$update_data['http2'] = $http2;
|
$update_data['http2'] = $http2;
|
||||||
$update_data['hsts'] = $hsts_maxage;
|
$update_data['hsts'] = $hsts_maxage;
|
||||||
@@ -1810,6 +1835,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$update_data['honorcipherorder'] = $honorcipherorder;
|
$update_data['honorcipherorder'] = $honorcipherorder;
|
||||||
$update_data['sessiontickets'] = $sessiontickets;
|
$update_data['sessiontickets'] = $sessiontickets;
|
||||||
$update_data['description'] = $description;
|
$update_data['description'] = $description;
|
||||||
|
$update_data['deactivated'] = $deactivated;
|
||||||
$update_data['id'] = $id;
|
$update_data['id'] = $id;
|
||||||
|
|
||||||
$update_stmt = Database::prepare("
|
$update_stmt = Database::prepare("
|
||||||
@@ -1830,6 +1856,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`iswildcarddomain` = :iswildcarddomain,
|
`iswildcarddomain` = :iswildcarddomain,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`speciallogfile` = :speciallogfile,
|
`speciallogfile` = :speciallogfile,
|
||||||
`phpsettingid` = :phpsettingid,
|
`phpsettingid` = :phpsettingid,
|
||||||
`mod_fcgid_starter` = :mod_fcgid_starter,
|
`mod_fcgid_starter` = :mod_fcgid_starter,
|
||||||
@@ -1842,7 +1869,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`writeerrorlog` = :writeerrorlog,
|
`writeerrorlog` = :writeerrorlog,
|
||||||
`registration_date` = :registration_date,
|
`registration_date` = :registration_date,
|
||||||
`termination_date` = :termination_date,
|
`termination_date` = :termination_date,
|
||||||
`ismainbutsubto` = :ismainbutsubto,
|
|
||||||
`letsencrypt` = :letsencrypt,
|
`letsencrypt` = :letsencrypt,
|
||||||
`http2` = :http2,
|
`http2` = :http2,
|
||||||
`hsts` = :hsts,
|
`hsts` = :hsts,
|
||||||
@@ -1856,15 +1882,41 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`ssl_enabled` = :sslenabled,
|
`ssl_enabled` = :sslenabled,
|
||||||
`ssl_honorcipherorder` = :honorcipherorder,
|
`ssl_honorcipherorder` = :honorcipherorder,
|
||||||
`ssl_sessiontickets` = :sessiontickets,
|
`ssl_sessiontickets` = :sessiontickets,
|
||||||
`description` = :description
|
`description` = :description,
|
||||||
|
`deactivated` = :deactivated
|
||||||
WHERE `id` = :id
|
WHERE `id` = :id
|
||||||
");
|
");
|
||||||
Database::pexecute($update_stmt, $update_data, true, true);
|
Database::pexecute($update_stmt, $update_data, true, true);
|
||||||
|
|
||||||
|
// activate/deactivate domain-based services
|
||||||
|
if ($deactivated != $result['deactivated']) {
|
||||||
|
// deactivate email accounts
|
||||||
|
$yesno = ($deactivated ? 'N' : 'Y');
|
||||||
|
$pop3 = ($deactivated ? '0' : (int)$customer['pop3']);
|
||||||
|
$imap = ($deactivated ? '0' : (int)$customer['imap']);
|
||||||
|
|
||||||
|
$upd_stmt = Database::prepare("
|
||||||
|
UPDATE `" . TABLE_MAIL_USERS . "`
|
||||||
|
SET `postfix`= :yesno, `pop3` = :pop3, `imap` = :imap
|
||||||
|
WHERE `customerid` = :customerid AND `domainid` = :domainid
|
||||||
|
");
|
||||||
|
Database::pexecute($upd_stmt, [
|
||||||
|
'yesno' => $yesno,
|
||||||
|
'pop3' => $pop3,
|
||||||
|
'imap' => $imap,
|
||||||
|
'customerid' => $customerid,
|
||||||
|
'domainid' => $id
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " domain '" . $result['domain'] . "'");
|
||||||
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
}
|
||||||
|
|
||||||
$_update_data['customerid'] = $customerid;
|
$_update_data['customerid'] = $customerid;
|
||||||
$_update_data['adminid'] = $adminid;
|
$_update_data['adminid'] = $adminid;
|
||||||
$_update_data['phpenabled'] = $phpenabled;
|
$_update_data['phpenabled'] = $phpenabled;
|
||||||
$_update_data['openbasedir'] = $openbasedir;
|
$_update_data['openbasedir'] = $openbasedir;
|
||||||
|
$_update_data['openbasedir_path'] = $openbasedir_path;
|
||||||
$_update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
$_update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
||||||
$_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests;
|
$_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests;
|
||||||
$_update_data['notryfiles'] = $notryfiles;
|
$_update_data['notryfiles'] = $notryfiles;
|
||||||
@@ -1877,6 +1929,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$_update_data['honorcipherorder'] = $honorcipherorder;
|
$_update_data['honorcipherorder'] = $honorcipherorder;
|
||||||
$_update_data['sessiontickets'] = $sessiontickets;
|
$_update_data['sessiontickets'] = $sessiontickets;
|
||||||
$_update_data['parentdomainid'] = $id;
|
$_update_data['parentdomainid'] = $id;
|
||||||
|
$_update_data['deactivated'] = $deactivated;
|
||||||
|
|
||||||
// if php config is to be set for all subdomains, check here
|
// if php config is to be set for all subdomains, check here
|
||||||
$update_phpconfig = '';
|
$update_phpconfig = '';
|
||||||
@@ -1898,6 +1951,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`adminid` = :adminid,
|
`adminid` = :adminid,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`mod_fcgid_starter` = :mod_fcgid_starter,
|
`mod_fcgid_starter` = :mod_fcgid_starter,
|
||||||
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
||||||
`notryfiles` = :notryfiles,
|
`notryfiles` = :notryfiles,
|
||||||
@@ -1908,12 +1962,25 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`ssl_cipher_list` = :ssl_cipher_list,
|
`ssl_cipher_list` = :ssl_cipher_list,
|
||||||
`tlsv13_cipher_list` = :tlsv13_cipher_list,
|
`tlsv13_cipher_list` = :tlsv13_cipher_list,
|
||||||
`ssl_honorcipherorder` = :honorcipherorder,
|
`ssl_honorcipherorder` = :honorcipherorder,
|
||||||
`ssl_sessiontickets` = :sessiontickets
|
`ssl_sessiontickets` = :sessiontickets,
|
||||||
|
`deactivated` = :deactivated
|
||||||
" . $update_phpconfig . $upd_specialsettings . $updatechildren . $update_sslredirect . "
|
" . $update_phpconfig . $upd_specialsettings . $updatechildren . $update_sslredirect . "
|
||||||
WHERE `parentdomainid` = :parentdomainid
|
WHERE `parentdomainid` = :parentdomainid
|
||||||
");
|
");
|
||||||
Database::pexecute($_update_stmt, $_update_data, true, true);
|
Database::pexecute($_update_stmt, $_update_data, true, true);
|
||||||
|
|
||||||
|
// get current ip<>domain entries
|
||||||
|
$ip_sel_stmt = Database::prepare("
|
||||||
|
SELECT id_ipandports FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
||||||
|
");
|
||||||
|
Database::pexecute($ip_sel_stmt, [
|
||||||
|
'id' => $id
|
||||||
|
], true, true);
|
||||||
|
$current_ips = [];
|
||||||
|
while ($cIP = $ip_sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$current_ips[] = $cIP['id_ipandports'];
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup domain <-> ip mapping
|
// Cleanup domain <-> ip mapping
|
||||||
$del_stmt = Database::prepare("
|
$del_stmt = Database::prepare("
|
||||||
DELETE FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
DELETE FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
||||||
@@ -1941,6 +2008,12 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check ip changes
|
||||||
|
$all_new_ips = array_merge($ipandports, $ssl_ipandports);
|
||||||
|
if (count(array_diff($current_ips, $all_new_ips)) != 0 || count(array_diff($all_new_ips, $current_ips)) != 0) {
|
||||||
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup domain <-> ip mapping for subdomains
|
// Cleanup domain <-> ip mapping for subdomains
|
||||||
$domainidsresult_stmt = Database::prepare("
|
$domainidsresult_stmt = Database::prepare("
|
||||||
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `parentdomainid` = :id
|
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `parentdomainid` = :id
|
||||||
@@ -2010,9 +2083,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, the domain-id
|
* optional, the domain-id
|
||||||
* @param string $domainname
|
* @param string $domainname
|
||||||
* optional, the domainname
|
* optional, the domainname
|
||||||
* @param bool $delete_mainsubdomains
|
|
||||||
* optional, remove also domains that are subdomains of this domain but added as main domains; default
|
|
||||||
* false
|
|
||||||
* @param bool $is_stdsubdomain
|
* @param bool $is_stdsubdomain
|
||||||
* optional, default false, specify whether it's a std-subdomain you are deleting as it does not count
|
* optional, default false, specify whether it's a std-subdomain you are deleting as it does not count
|
||||||
* as subdomain-resource
|
* as subdomain-resource
|
||||||
@@ -2028,7 +2098,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$dn_optional = $id > 0;
|
$dn_optional = $id > 0;
|
||||||
$domainname = $this->getParam('domainname', $dn_optional, '');
|
$domainname = $this->getParam('domainname', $dn_optional, '');
|
||||||
$is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0);
|
$is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0);
|
||||||
$remove_subbutmain_domains = $this->getParam('delete_mainsubdomains', true, 0);
|
|
||||||
|
|
||||||
$result = $this->apiCall('Domains.get', [
|
$result = $this->apiCall('Domains.get', [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
@@ -2036,15 +2105,10 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
]);
|
]);
|
||||||
$id = $result['id'];
|
$id = $result['id'];
|
||||||
|
|
||||||
// check for deletion of main-domains which are logically subdomains, #329
|
|
||||||
$rsd_sql = '';
|
|
||||||
if ($remove_subbutmain_domains) {
|
|
||||||
$rsd_sql .= " OR `ismainbutsubto` = :id";
|
|
||||||
}
|
|
||||||
|
|
||||||
$subresult_stmt = Database::prepare("
|
$subresult_stmt = Database::prepare("
|
||||||
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "`
|
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE (`id` = :id OR `parentdomainid` = :id " . $rsd_sql . ")");
|
WHERE (`id` = :id OR `parentdomainid` = :id)
|
||||||
|
");
|
||||||
Database::pexecute($subresult_stmt, [
|
Database::pexecute($subresult_stmt, [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
@@ -2066,23 +2130,10 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] deleted domain/s from mail-tables");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] deleted domain/s from mail-tables");
|
||||||
}
|
}
|
||||||
|
|
||||||
// if mainbutsubto-domains are not to be deleted, re-assign the (ismainbutsubto value of the main
|
|
||||||
// domain which is being deleted) as their new ismainbutsubto value
|
|
||||||
if ($remove_subbutmain_domains !== 1) {
|
|
||||||
$upd_stmt = Database::prepare("
|
|
||||||
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
|
|
||||||
`ismainbutsubto` = :newIsMainButSubtoValue
|
|
||||||
WHERE `ismainbutsubto` = :deletedMainDomainId
|
|
||||||
");
|
|
||||||
Database::pexecute($upd_stmt, [
|
|
||||||
'newIsMainButSubtoValue' => $result['ismainbutsubto'],
|
|
||||||
'deletedMainDomainId' => $id
|
|
||||||
], true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$del_stmt = Database::prepare("
|
$del_stmt = Database::prepare("
|
||||||
DELETE FROM `" . TABLE_PANEL_DOMAINS . "`
|
DELETE FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE `id` = :id OR `parentdomainid` = :id " . $rsd_sql);
|
WHERE `id` = :id OR `parentdomainid` = :id
|
||||||
|
");
|
||||||
Database::pexecute($del_stmt, [
|
Database::pexecute($del_stmt, [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
@@ -2158,7 +2209,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
// remove domain from acme.sh / lets encrypt if used
|
// remove domain from acme.sh / lets encrypt if used
|
||||||
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $result['domain']);
|
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $result['domain']);
|
||||||
|
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] deleted domain/subdomains (#" . $result['id'] . ")");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted domain/subdomains (#" . $result['id'] . ")");
|
||||||
User::updateCounters();
|
User::updateCounters();
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
// Using nameserver, insert a task which rebuilds the server config
|
// Using nameserver, insert a task which rebuilds the server config
|
||||||
@@ -2167,4 +2218,114 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* duplicate domain entry by either id or domainname. All parameters from Domains.add() can be used
|
||||||
|
* to overwrite source entity values if necessary.
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* optional, the domain-id
|
||||||
|
* @param string $domainname
|
||||||
|
* optional, the domainname
|
||||||
|
* @param string $domain
|
||||||
|
* required, name of the new domain to be added
|
||||||
|
*
|
||||||
|
* @access admin
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function duplicate()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin()) {
|
||||||
|
// parameters
|
||||||
|
$id = $this->getParam('id', true, 0);
|
||||||
|
$dn_optional = $id > 0;
|
||||||
|
$domainname = $this->getParam('domainname', $dn_optional, '');
|
||||||
|
$p_domain = $this->getParam('domain');
|
||||||
|
|
||||||
|
// get requested domain
|
||||||
|
$result = $this->apiCall('Domains.get', [
|
||||||
|
'id' => $id,
|
||||||
|
'domainname' => $domainname,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// clear some defaults
|
||||||
|
unset($result['domain_ace']);
|
||||||
|
unset($result['adminid']);
|
||||||
|
unset($result['documentroot']);
|
||||||
|
unset($result['registration_date']);
|
||||||
|
unset($result['termination_date']);
|
||||||
|
unset($result['zonefile']);
|
||||||
|
// clear auto-generated values
|
||||||
|
unset($result['bindserial']);
|
||||||
|
unset($result['dkim_privkey']);
|
||||||
|
unset($result['dkim_pubkey']);
|
||||||
|
// clear api-call generated fields
|
||||||
|
unset($result['domain_hascert']);
|
||||||
|
|
||||||
|
// set correct ip/port information
|
||||||
|
$domain_ips = $result['ipsandports'];
|
||||||
|
unset($result['ipsandports']);
|
||||||
|
$result['ipandport'] = [];
|
||||||
|
$result['ssl_ipandport'] = [];
|
||||||
|
foreach ($domain_ips as $dip) {
|
||||||
|
if ($dip['ssl'] == 1) {
|
||||||
|
$result['ssl_ipandport'][] = $dip['id'];
|
||||||
|
} else {
|
||||||
|
$result['ipandport'][] = $dip['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether we are changing the customer/owner
|
||||||
|
if ($this->getParam('customerid', true, 0) == 0 && $this->getParam('loginname', true, '') == '') {
|
||||||
|
$customerid = $result['customerid'];
|
||||||
|
} else {
|
||||||
|
$customer = $this->getCustomerData();
|
||||||
|
$customerid = $customer['customerid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for alias-domain and whether it belongs to the target user
|
||||||
|
if (!empty($result['aliasdomain']) && $customerid == $result['customerid']) {
|
||||||
|
// duplicate alias entry
|
||||||
|
$result['alias'] = $result['aliasdomain'];
|
||||||
|
}
|
||||||
|
unset($result['aliasdomain']);
|
||||||
|
|
||||||
|
// validate possible fpm configs and whether the customer is allowed to use them
|
||||||
|
if ($customerid != $result['customerid']) {
|
||||||
|
$allowed_phpconfigs = json_decode($customer['allowed_phpconfigs'] ?? '[]', true);
|
||||||
|
if (empty($allowed_phpconfigs)) {
|
||||||
|
// system defaults
|
||||||
|
unset($result['phpsettingid']);
|
||||||
|
} elseif (!in_array($result['phpsettingid'], $allowed_phpconfigs)) {
|
||||||
|
// use the first customer allowed config
|
||||||
|
$result['phpsettingid'] = array_shift($allowed_phpconfigs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate serveralias values
|
||||||
|
$result['selectserveralias'] = 2;
|
||||||
|
if ((int)$result['wwwserveralias'] == 1) {
|
||||||
|
$result['selectserveralias'] = 1;
|
||||||
|
} elseif ((int)$result['iswildcarddomain'] == 1) {
|
||||||
|
$result['selectserveralias'] = 0;
|
||||||
|
}
|
||||||
|
unset($result['wwwserveralias']);
|
||||||
|
unset($result['iswildcarddomain']);
|
||||||
|
|
||||||
|
$additional_params = $this->getParamList();
|
||||||
|
// unset unneeded params from this call
|
||||||
|
unset($additional_params['id']);
|
||||||
|
unset($additional_params['domainname']);
|
||||||
|
unset($additional_params['domain']);
|
||||||
|
|
||||||
|
// set new values and merge with optional add() parameters
|
||||||
|
$new_domain = array_merge($result, $additional_params);
|
||||||
|
$new_domain['domain'] = $p_domain;
|
||||||
|
|
||||||
|
$result_new = $this->apiCall('Domains.add', $new_domain);
|
||||||
|
return $this->response($result_new);
|
||||||
|
}
|
||||||
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
* @param string $alternative_email
|
* @param string $alternative_email
|
||||||
* optional email address to send account information to, default is the account that is being created
|
* optional email address to send account information to, default is the account that is being created
|
||||||
* @param int $email_quota
|
* @param int $email_quota
|
||||||
* optional quota if enabled in MB, default 0
|
* optional quota if enabled in MB, default setting: system.mail_quota
|
||||||
* @param bool $sendinfomail
|
* @param bool $sendinfomail
|
||||||
* optional, sends the welcome message to the new account (needed for creation, without the user won't
|
* optional, sends the welcome message to the new account (needed for creation, without the user won't
|
||||||
* be able to login before any mail is received), default 1 (true)
|
* be able to login before any mail is received), default 1 (true)
|
||||||
@@ -85,7 +85,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
||||||
$email_password = $this->getParam('email_password');
|
$email_password = $this->getParam('email_password');
|
||||||
$alternative_email = $this->getParam('alternative_email', true, '');
|
$alternative_email = $this->getParam('alternative_email', true, '');
|
||||||
$quota = $this->getParam('email_quota', true, 0);
|
$quota = $this->getParam('email_quota', true, Settings::Get('system.mail_quota') ?? 0);
|
||||||
$sendinfomail = $this->getBoolParam('sendinfomail', true, 1);
|
$sendinfomail = $this->getBoolParam('sendinfomail', true, 1);
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
@@ -95,9 +95,18 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
$customer = $this->getCustomerData('email_accounts');
|
$customer = $this->getCustomerData('email_accounts');
|
||||||
|
|
||||||
// check for imap||pop3 == 1, see #1298
|
// check for imap||pop3 == 1, see #1298
|
||||||
|
// d00p, 6.5.2023 @revert this - if a customer has resources which allow email accounts
|
||||||
|
// it implicitly allowed SMTP, e.g. sending of emails which also requires an account to exist
|
||||||
|
/*
|
||||||
if ($customer['imap'] != '1' && $customer['pop3'] != '1') {
|
if ($customer['imap'] != '1' && $customer['pop3'] != '1') {
|
||||||
Response::standardError('notallowedtouseaccounts', '', true);
|
Response::standardError('notallowedtouseaccounts', '', true);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!empty($emailaddr)) {
|
||||||
|
$idna_convert = new IdnaWrapper();
|
||||||
|
$emailaddr = $idna_convert->encode($emailaddr);
|
||||||
|
}
|
||||||
|
|
||||||
// get email address
|
// get email address
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
@@ -306,7 +315,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email account for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email account for '" . $result['email_full'] . "'");
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
]);
|
]);
|
||||||
@@ -357,6 +366,11 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
$ea_optional = $id > 0;
|
$ea_optional = $id > 0;
|
||||||
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
||||||
|
|
||||||
|
if (!empty($emailaddr)) {
|
||||||
|
$idna_convert = new IdnaWrapper();
|
||||||
|
$emailaddr = $idna_convert->encode($emailaddr);
|
||||||
|
}
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
@@ -450,7 +464,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
Admins::increaseUsage($customer['adminid'], 'email_quota_used', '', ($quota - $result['quota']));
|
Admins::increaseUsage($customer['adminid'], 'email_quota_used', '', ($quota - $result['quota']));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated email account '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated email account '" . $result['email_full'] . "'");
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
]);
|
]);
|
||||||
@@ -556,7 +570,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
Customers::decreaseUsage($customer['customerid'], 'email_accounts_used');
|
Customers::decreaseUsage($customer['customerid'], 'email_accounts_used');
|
||||||
Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $quota);
|
Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $quota);
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email account for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted email account for '" . $result['email_full'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class EmailDomains extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE,
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO,
|
||||||
"[API] list email-domains");
|
"[API] list email-domains");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
|
|||||||
@@ -77,6 +77,11 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
|
|||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
$destination = $idna_convert->encode($destination);
|
$destination = $idna_convert->encode($destination);
|
||||||
|
|
||||||
|
if (!empty($emailaddr)) {
|
||||||
|
$idna_convert = new IdnaWrapper();
|
||||||
|
$emailaddr = $idna_convert->encode($emailaddr);
|
||||||
|
}
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'emailaddr' => $emailaddr
|
'emailaddr' => $emailaddr
|
||||||
@@ -116,7 +121,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
|
|||||||
// update customer usage
|
// update customer usage
|
||||||
Customers::increaseUsage($customer['customerid'], 'email_forwarders_used');
|
Customers::increaseUsage($customer['customerid'], 'email_forwarders_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email forwarder for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email forwarder for '" . $result['email_full'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
@@ -293,7 +298,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
|
|||||||
// update customer usage
|
// update customer usage
|
||||||
Customers::decreaseUsage($customer['customerid'], 'email_forwarders_used');
|
Customers::decreaseUsage($customer['customerid'], 'email_forwarders_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email forwarder for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted email forwarder for '" . $result['email_full'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
|
|||||||
@@ -88,9 +88,12 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
$domain_check = $this->apiCall('SubDomains.get', [
|
$domain_check = $this->apiCall('SubDomains.get', [
|
||||||
'domainname' => $domain
|
'domainname' => $domain
|
||||||
], true);
|
], true);
|
||||||
if ($domain_check['isemaildomain'] == 0) {
|
if ((int)$domain_check['isemaildomain'] == 0) {
|
||||||
Response::standardError('maindomainnonexist', $domain, true);
|
Response::standardError('maindomainnonexist', $domain, true);
|
||||||
}
|
}
|
||||||
|
if ((int)$domain_check['deactivated'] == 1) {
|
||||||
|
Response::standardError('maindomaindeactivated', $domain, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (Settings::Get('catchall.catchall_enabled') != '1') {
|
if (Settings::Get('catchall.catchall_enabled') != '1') {
|
||||||
$iscatchall = 0;
|
$iscatchall = 0;
|
||||||
@@ -159,7 +162,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
// update customer usage
|
// update customer usage
|
||||||
Customers::increaseUsage($customer['customerid'], 'emails_used');
|
Customers::increaseUsage($customer['customerid'], 'emails_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email address '" . $email_full . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email address '" . $email_full . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $email_full
|
'emailaddr' => $email_full
|
||||||
@@ -195,11 +198,11 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
FROM `" . TABLE_MAIL_VIRTUAL . "` v
|
FROM `" . TABLE_MAIL_VIRTUAL . "` v
|
||||||
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
|
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
|
||||||
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
|
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
|
||||||
AND (v.`id`= :idea OR (v.`email` = :idea OR v.`email_full` = :idea))
|
AND " . (is_numeric($params['idea']) ? "v.`id`= :idea" : "(v.`email` = :idea OR v.`email_full` = :idea)")
|
||||||
");
|
);
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get email address '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get email address '" . $result['email_full'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'");
|
$key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'");
|
||||||
@@ -294,7 +297,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id
|
"id" => $id
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
@@ -340,7 +343,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list email-addresses");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list email-addresses");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -445,7 +448,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
], true, true);
|
], true, true);
|
||||||
Customers::decreaseUsage($customer['customerid'], 'emails_used');
|
Customers::decreaseUsage($customer['customerid'], 'emails_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email address '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted email address '" . $result['email_full'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list fpm-daemons");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list fpm-daemons");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "`" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "`" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
||||||
@@ -258,7 +258,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
$id = Database::lastInsertId();
|
$id = Database::lastInsertId();
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
||||||
$result = $this->apiCall('FpmDaemons.get', [
|
$result = $this->apiCall('FpmDaemons.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -384,7 +384,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
Database::pexecute($upd_stmt, $upd_data, true, true);
|
Database::pexecute($upd_stmt, $upd_data, true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
||||||
$result = $this->apiCall('FpmDaemons.get', [
|
$result = $this->apiCall('FpmDaemons.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -433,7 +433,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ use Froxlor\Settings;
|
|||||||
use Froxlor\SImExporter;
|
use Froxlor\SImExporter;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\Crypt;
|
use Froxlor\System\Crypt;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
use PDO;
|
use PDO;
|
||||||
use RecursiveDirectoryIterator;
|
use RecursiveDirectoryIterator;
|
||||||
use RecursiveIteratorIterator;
|
use RecursiveIteratorIterator;
|
||||||
@@ -72,7 +73,7 @@ class Froxlor extends ApiCommand
|
|||||||
|
|
||||||
if (empty($uc_data) || empty($response) || $uc_data['ts'] + self::UPDATE_CHECK_INTERVAL < time() || $uc_data['channel'] != Settings::Get('system.update_channel') || $force_ucheck) {
|
if (empty($uc_data) || empty($response) || $uc_data['ts'] + self::UPDATE_CHECK_INTERVAL < time() || $uc_data['channel'] != Settings::Get('system.update_channel') || $force_ucheck) {
|
||||||
// log our actions
|
// log our actions
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] checking for updates");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] checking for updates");
|
||||||
|
|
||||||
// check for new version
|
// check for new version
|
||||||
$aucheck = AutoUpdate::checkVersion();
|
$aucheck = AutoUpdate::checkVersion();
|
||||||
@@ -142,7 +143,7 @@ class Froxlor extends ApiCommand
|
|||||||
{
|
{
|
||||||
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
|
||||||
$json_str = $this->getParam('json_str');
|
$json_str = $this->getParam('json_str');
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "User " . $this->getUserDetail('loginname') . " imported settings");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "User " . $this->getUserDetail('loginname') . " imported settings");
|
||||||
try {
|
try {
|
||||||
SImExporter::import($json_str);
|
SImExporter::import($json_str);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
@@ -269,6 +270,79 @@ class Froxlor extends ApiCommand
|
|||||||
return $this->response(Crypt::generatePassword($length));
|
return $this->response(Crypt::generatePassword($length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a one-time login link URL for a given user
|
||||||
|
*
|
||||||
|
* @param int $customerid optional, required if $loginname is not specified, user to create link for
|
||||||
|
* @param string $loginname optional, required if $customerid is not specified, user to create link for
|
||||||
|
* @param int $valid_time optional, value in seconds how long the link will be valid, default is 10 seconds, valid values are numbers from 10 to 120
|
||||||
|
* @param string $allowed_from optional, comma separated list of ip addresses or networks to allow login from via this link
|
||||||
|
*
|
||||||
|
* @access admin
|
||||||
|
* @return string json-encoded array [base => domain, uri => relative link]
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function generateLoginLink()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin()) {
|
||||||
|
$customer = $this->getCustomerData();
|
||||||
|
|
||||||
|
// cannot create link for deactivated users
|
||||||
|
if ((int)$customer['deactivated'] == 1) {
|
||||||
|
throw new Exception("Cannot generate link for deactivated user", 406);
|
||||||
|
}
|
||||||
|
|
||||||
|
$valid_time = (int)$this->getParam('valid_time', true, 10);
|
||||||
|
$allowed_from = $this->getParam('allowed_from', true, '');
|
||||||
|
|
||||||
|
$valid_time = Validate::validate($valid_time, 'valid time', '/^(1[0-1][0-9]|120|[1-9][0-9])$/', 'invalid_validtime', [10], true);
|
||||||
|
|
||||||
|
// validate allowed_from
|
||||||
|
if (!empty($allowed_from)) {
|
||||||
|
$ip_list = array_map('trim', explode(",", $allowed_from));
|
||||||
|
$_check_list = $ip_list;
|
||||||
|
foreach ($_check_list as $idx => $ip) {
|
||||||
|
if (Validate::validate_ip2($ip, true, 'invalidip', true, true, true) == false) {
|
||||||
|
throw new Exception('Invalid ip address', 406);
|
||||||
|
}
|
||||||
|
// check for cidr
|
||||||
|
if (strpos($ip, '/') !== false) {
|
||||||
|
$ipparts = explode("/", $ip);
|
||||||
|
// shorten IP
|
||||||
|
$ip = inet_ntop(inet_pton($ipparts[0]));
|
||||||
|
// re-add cidr
|
||||||
|
$ip .= '/' . $ipparts[1];
|
||||||
|
} else {
|
||||||
|
// shorten IP
|
||||||
|
$ip = inet_ntop(inet_pton($ip));
|
||||||
|
}
|
||||||
|
$ip_list[$idx] = $ip;
|
||||||
|
}
|
||||||
|
$allowed_from = implode(",", array_unique($ip_list));
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash = hash('sha256', openssl_random_pseudo_bytes(64 * 64));
|
||||||
|
|
||||||
|
$ins_stmt = Database::prepare("
|
||||||
|
INSERT INTO `" . TABLE_PANEL_LOGINLINKS . "`
|
||||||
|
SET `hash` = :hash, `loginname` = :loginname, `valid_until` = :validuntil, `allowed_from` = :allowedfrom
|
||||||
|
ON DUPLICATE KEY UPDATE `hash` = :hash, `valid_until` = :validuntil, `allowed_from` = :allowedfrom
|
||||||
|
");
|
||||||
|
Database::pexecute($ins_stmt, [
|
||||||
|
'hash' => $hash,
|
||||||
|
'loginname' => $customer['loginname'],
|
||||||
|
'validuntil' => time() + $valid_time,
|
||||||
|
'allowedfrom' => $allowed_from
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->response([
|
||||||
|
'base' => 'https://' . Settings::Get('system.hostname') . '/' . (Settings::Get('system.froxlordirectlyviahostname') != 1 ? basename(\Froxlor\Froxlor::getInstallDir()) . '/' : ''),
|
||||||
|
'uri' => 'index.php?action=ll&ln=' . $customer['loginname'] . '&h=' . $hash
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* can be used to remotely run the integritiy checks froxlor implements
|
* can be used to remotely run the integritiy checks froxlor implements
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
* optional whether to add additional usernames to the group
|
* optional whether to add additional usernames to the group
|
||||||
* @param bool $is_defaultuser
|
* @param bool $is_defaultuser
|
||||||
* optional whether this is the standard default ftp user which is being added so no usage is decreased
|
* optional whether this is the standard default ftp user which is being added so no usage is decreased
|
||||||
|
* @param bool $login_enabled
|
||||||
|
* optional whether to allow login (default) or not
|
||||||
*
|
*
|
||||||
* @access admin, customer
|
* @access admin, customer
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
@@ -84,6 +86,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
$is_defaultuser = $this->getBoolParam('is_defaultuser', true, 0);
|
$is_defaultuser = $this->getBoolParam('is_defaultuser', true, 0);
|
||||||
|
$login_enabled = $this->getBoolParam('login_enabled', true, 1);
|
||||||
|
|
||||||
if (($this->getUserDetail('ftps_used') < $this->getUserDetail('ftps') || $this->getUserDetail('ftps') == '-1') || $this->isAdmin() && $is_defaultuser == 1) {
|
if (($this->getUserDetail('ftps_used') < $this->getUserDetail('ftps') || $this->getUserDetail('ftps') == '-1') || $this->isAdmin() && $is_defaultuser == 1) {
|
||||||
// required parameters
|
// required parameters
|
||||||
@@ -176,13 +179,14 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
$stmt = Database::prepare("INSERT INTO `" . TABLE_FTP_USERS . "`
|
$stmt = Database::prepare("INSERT INTO `" . TABLE_FTP_USERS . "`
|
||||||
(`customerid`, `username`, `description`, `password`, `homedir`, `login_enabled`, `uid`, `gid`, `shell`)
|
(`customerid`, `username`, `description`, `password`, `homedir`, `login_enabled`, `uid`, `gid`, `shell`)
|
||||||
VALUES (:customerid, :username, :description, :password, :homedir, 'y', :guid, :guid, :shell)");
|
VALUES (:customerid, :username, :description, :password, :homedir, :loginenabled, :guid, :guid, :shell)");
|
||||||
$params = [
|
$params = [
|
||||||
"customerid" => $customer['customerid'],
|
"customerid" => $customer['customerid'],
|
||||||
"username" => $username,
|
"username" => $username,
|
||||||
"description" => $description,
|
"description" => $description,
|
||||||
"password" => $cryptPassword,
|
"password" => $cryptPassword,
|
||||||
"homedir" => $path,
|
"homedir" => $path,
|
||||||
|
"loginenabled" => $login_enabled ? 'Y' : 'N',
|
||||||
"guid" => $customer['guid'],
|
"guid" => $customer['guid'],
|
||||||
"shell" => $shell
|
"shell" => $shell
|
||||||
];
|
];
|
||||||
@@ -257,7 +261,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
Customers::increaseUsage($customer['customerid'], 'ftp_lastaccountnumber');
|
Customers::increaseUsage($customer['customerid'], 'ftp_lastaccountnumber');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ftp-account '" . $username . " (" . $path . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ftp-account '" . $username . " (" . $path . ")'");
|
||||||
Cronjob::inserttask(TaskId::CREATE_FTP);
|
Cronjob::inserttask(TaskId::CREATE_FTP);
|
||||||
|
|
||||||
if ($sendinfomail == 1) {
|
if ($sendinfomail == 1) {
|
||||||
@@ -302,7 +306,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
$this->mailer()->clearAddresses();
|
$this->mailer()->clearAddresses();
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] added ftp-user '" . $username . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ftp-user '" . $username . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Ftps.get', [
|
$result = $this->apiCall('Ftps.get', [
|
||||||
'username' => $username
|
'username' => $username
|
||||||
@@ -367,7 +371,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
$params['idun'] = ($id <= 0 ? $username : $id);
|
$params['idun'] = ($id <= 0 ? $username : $id);
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get ftp-user '" . $result['username'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get ftp-user '" . $result['username'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
||||||
@@ -389,6 +393,8 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
* optional, description for ftp-user
|
* optional, description for ftp-user
|
||||||
* @param string $shell
|
* @param string $shell
|
||||||
* optional, default /bin/false (not changeable when deactivated)
|
* optional, default /bin/false (not changeable when deactivated)
|
||||||
|
* @param bool $login_enabled
|
||||||
|
* optional whether to allow login (default) or not
|
||||||
* @param int $customerid
|
* @param int $customerid
|
||||||
* optional, required when called as admin (if $loginname is not specified)
|
* optional, required when called as admin (if $loginname is not specified)
|
||||||
* @param string $loginname
|
* @param string $loginname
|
||||||
@@ -419,6 +425,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
$password = $this->getParam('ftp_password', true, '');
|
$password = $this->getParam('ftp_password', true, '');
|
||||||
$description = $this->getParam('ftp_description', true, $result['description']);
|
$description = $this->getParam('ftp_description', true, $result['description']);
|
||||||
$shell = $this->getParam('shell', true, $result['shell']);
|
$shell = $this->getParam('shell', true, $result['shell']);
|
||||||
|
$login_enabled = $this->getBoolParam('login_enabled', true, ($result['login_enabled'] == 'Y' ? 1 : 0));
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$password = Validate::validate($password, 'password', '', '', [], true);
|
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||||
@@ -430,6 +437,10 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
$shell = "/bin/false";
|
$shell = "/bin/false";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($login_enabled != 1) {
|
||||||
|
$login_enabled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// get needed customer info to reduce the ftp-user-counter by one
|
// get needed customer info to reduce the ftp-user-counter by one
|
||||||
$customer = $this->getCustomerData();
|
$customer = $this->getCustomerData();
|
||||||
|
|
||||||
@@ -453,7 +464,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id,
|
"id" => $id,
|
||||||
"password" => $cryptPassword
|
"password" => $cryptPassword
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ftp-account password for '" . $result['username'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-account password for '" . $result['username'] . "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// path update?
|
// path update?
|
||||||
@@ -471,7 +482,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
"customerid" => $customer['customerid'],
|
"customerid" => $customer['customerid'],
|
||||||
"id" => $id
|
"id" => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ftp-account homdir for '" . $result['username'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-account homdir for '" . $result['username'] . "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// it's the task for "new ftp" but that will
|
// it's the task for "new ftp" but that will
|
||||||
@@ -480,13 +491,14 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
$stmt = Database::prepare("
|
$stmt = Database::prepare("
|
||||||
UPDATE `" . TABLE_FTP_USERS . "`
|
UPDATE `" . TABLE_FTP_USERS . "`
|
||||||
SET `description` = :desc, `shell` = :shell
|
SET `description` = :desc, `shell` = :shell, `login_enabled` = :loginenabled
|
||||||
WHERE `customerid` = :customerid
|
WHERE `customerid` = :customerid
|
||||||
AND `id` = :id
|
AND `id` = :id
|
||||||
");
|
");
|
||||||
Database::pexecute($stmt, [
|
Database::pexecute($stmt, [
|
||||||
"desc" => $description,
|
"desc" => $description,
|
||||||
"shell" => $shell,
|
"shell" => $shell,
|
||||||
|
"loginenabled" => $login_enabled ? 'Y' : 'N',
|
||||||
"customerid" => $customer['customerid'],
|
"customerid" => $customer['customerid'],
|
||||||
"id" => $id
|
"id" => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
@@ -533,7 +545,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list ftp-users");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list ftp-users");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list hosting-plans");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list hosting-plans");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT p.*, a.loginname as adminname
|
SELECT p.*, a.loginname as adminname
|
||||||
@@ -200,8 +200,8 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, 0);
|
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, 0);
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$name = Validate::validate(trim($name), 'name', '', '', [], true);
|
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT);
|
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_CONF_TEXT);
|
||||||
|
|
||||||
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
||||||
$value_arr['email_quota'] = -1;
|
$value_arr['email_quota'] = -1;
|
||||||
@@ -227,7 +227,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
'valuearr' => json_encode($value_arr)
|
'valuearr' => json_encode($value_arr)
|
||||||
];
|
];
|
||||||
Database::pexecute($ins_stmt, $ins_data, true, true);
|
Database::pexecute($ins_stmt, $ins_data, true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added hosting-plan '" . $name . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] added hosting-plan '" . $name . "'");
|
||||||
$result = $this->apiCall('HostingPlans.get', [
|
$result = $this->apiCall('HostingPlans.get', [
|
||||||
'planname' => $name
|
'planname' => $name
|
||||||
]);
|
]);
|
||||||
@@ -264,7 +264,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get hosting-plan '" . $result['name'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get hosting-plan '" . $result['name'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "planname '" . $planname . "'");
|
$key = ($id > 0 ? "id #" . $id : "planname '" . $planname . "'");
|
||||||
@@ -382,8 +382,8 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, $result['logviewenabled']);
|
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, $result['logviewenabled']);
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$name = Validate::validate(trim($name), 'name', '', '', [], true);
|
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT);
|
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_CONF_TEXT);
|
||||||
|
|
||||||
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
||||||
$value_arr['email_quota'] = -1;
|
$value_arr['email_quota'] = -1;
|
||||||
@@ -414,7 +414,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
'id' => $id
|
'id' => $id
|
||||||
];
|
];
|
||||||
Database::pexecute($upd_stmt, $update_data, true, true);
|
Database::pexecute($upd_stmt, $update_data, true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] updated hosting-plan '" . $result['name'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] updated hosting-plan '" . $result['name'] . "'");
|
||||||
return $this->response($update_data);
|
return $this->response($update_data);
|
||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin() && ($this->getUserDetail('change_serversettings') || !empty($this->getUserDetail('ip')))) {
|
if ($this->isAdmin() && ($this->getUserDetail('change_serversettings') || !empty($this->getUserDetail('ip')))) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list ips and ports");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list ips and ports");
|
||||||
$ip_where = "";
|
$ip_where = "";
|
||||||
$append_where = false;
|
$append_where = false;
|
||||||
if (!empty($this->getUserDetail('ip')) && $this->getUserDetail('ip') != -1) {
|
if (!empty($this->getUserDetail('ip')) && $this->getUserDetail('ip') != -1) {
|
||||||
@@ -175,9 +175,9 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
$docroot = Validate::validate($this->getParam('docroot', true, ''), 'docroot', Validate::REGEX_DIR, '', [], true);
|
$docroot = Validate::validate($this->getParam('docroot', true, ''), 'docroot', Validate::REGEX_DIR, '', [], true);
|
||||||
|
|
||||||
if ((int)Settings::Get('system.use_ssl') == 1) {
|
if ((int)Settings::Get('system.use_ssl') == 1) {
|
||||||
$ssl = !empty($this->getBoolParam('ssl', true, 0)) ? intval($this->getBoolParam('ssl', true, 0)) : 0;
|
$ssl = (bool)$this->getBoolParam('ssl', true, 0);
|
||||||
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', $ssl, ''), 'ssl_cert_file', '', '', [], true);
|
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', !$ssl, ''), 'ssl_cert_file', '', '', [], true);
|
||||||
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', $ssl, ''), 'ssl_key_file', '', '', [], true);
|
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', !$ssl, ''), 'ssl_key_file', '', '', [], true);
|
||||||
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, ''), 'ssl_ca_file', '', '', [], true);
|
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, ''), 'ssl_ca_file', '', '', [], true);
|
||||||
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, ''), 'ssl_cert_chainfile', '', '', [], true);
|
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, ''), 'ssl_cert_chainfile', '', '', [], true);
|
||||||
$sslss = $this->getParam('ssl_specialsettings', true, '');
|
$sslss = $this->getParam('ssl_specialsettings', true, '');
|
||||||
@@ -335,7 +335,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
'id' => $id
|
'id' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get ip " . $result['ip'] . " " . $result['port']);
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get ip " . $result['ip'] . " " . $result['port']);
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("IP/port with id #" . $id . " could not be found", 404);
|
throw new Exception("IP/port with id #" . $id . " could not be found", 404);
|
||||||
@@ -414,9 +414,9 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
$docroot = Validate::validate($this->getParam('docroot', true, $result['docroot']), 'docroot', Validate::REGEX_DIR, '', [], true);
|
$docroot = Validate::validate($this->getParam('docroot', true, $result['docroot']), 'docroot', Validate::REGEX_DIR, '', [], true);
|
||||||
|
|
||||||
if ((int)Settings::Get('system.use_ssl') == 1) {
|
if ((int)Settings::Get('system.use_ssl') == 1) {
|
||||||
$ssl = $this->getBoolParam('ssl', true, $result['ssl']);
|
$ssl = (bool)$this->getBoolParam('ssl', true, $result['ssl']);
|
||||||
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', $ssl, $result['ssl_cert_file']), 'ssl_cert_file', '', '', [], true);
|
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', !$ssl, $result['ssl_cert_file']), 'ssl_cert_file', '', '', [], true);
|
||||||
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', $ssl, $result['ssl_key_file']), 'ssl_key_file', '', '', [], true);
|
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', !$ssl, $result['ssl_key_file']), 'ssl_key_file', '', '', [], true);
|
||||||
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, $result['ssl_ca_file']), 'ssl_ca_file', '', '', [], true);
|
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, $result['ssl_ca_file']), 'ssl_ca_file', '', '', [], true);
|
||||||
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, $result['ssl_cert_chainfile']), 'ssl_cert_chainfile', '', '', [], true);
|
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, $result['ssl_cert_chainfile']), 'ssl_cert_chainfile', '', '', [], true);
|
||||||
$sslss = $this->getParam('ssl_specialsettings', true, $result['ssl_specialsettings']);
|
$sslss = $this->getParam('ssl_specialsettings', true, $result['ssl_specialsettings']);
|
||||||
|
|||||||
@@ -26,14 +26,15 @@
|
|||||||
namespace Froxlor\Api\Commands;
|
namespace Froxlor\Api\Commands;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use PDO;
|
|
||||||
use PDOException;
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\PhpHelper;
|
|
||||||
use Froxlor\Api\ApiCommand;
|
use Froxlor\Api\ApiCommand;
|
||||||
use Froxlor\Api\ResourceEntity;
|
use Froxlor\Api\ResourceEntity;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\PhpHelper;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
|
|
||||||
class MysqlServer extends ApiCommand implements ResourceEntity
|
class MysqlServer extends ApiCommand implements ResourceEntity
|
||||||
{
|
{
|
||||||
@@ -73,8 +74,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional, test connection with given credentials, default is true (yes)
|
* optional, test connection with given credentials, default is true (yes)
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function add()
|
public function add()
|
||||||
{
|
{
|
||||||
@@ -112,7 +113,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
);
|
);
|
||||||
if (!empty($mysql_ca)) {
|
if (!empty($mysql_ca)) {
|
||||||
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
||||||
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool) $mysql_verifycert;
|
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool)$mysql_verifycert;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
||||||
@@ -167,6 +168,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
$this->addDatabaseFromCustomerAllowedList($newdbserver);
|
$this->addDatabaseFromCustomerAllowedList($newdbserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added new database server '" . $description . "' (" . $mysql_host . ")");
|
||||||
|
|
||||||
return $this->response(['dbserver' => $newdbserver]);
|
return $this->response(['dbserver' => $newdbserver]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,16 +182,16 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional the number of the mysql server (either id or dbserver must be set)
|
* optional the number of the mysql server (either id or dbserver must be set)
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
$this->validateAccess();
|
$this->validateAccess();
|
||||||
|
|
||||||
$id = (int) $this->getParam('id', true, -1);
|
$id = (int)$this->getParam('id', true, -1);
|
||||||
$dn_optional = $id >= 0;
|
$dn_optional = $id >= 0;
|
||||||
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
|
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
|
||||||
$dbserver = $id >= 0 ? $id : $dbserver;
|
$dbserver = $id >= 0 ? $id : $dbserver;
|
||||||
|
|
||||||
if ($dbserver == 0) {
|
if ($dbserver == 0) {
|
||||||
@@ -212,8 +215,12 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
// when removing, remove from list of allowed_mysqlservers from any customers
|
// when removing, remove from list of allowed_mysqlservers from any customers
|
||||||
$this->removeDatabaseFromCustomerAllowedList($dbserver);
|
$this->removeDatabaseFromCustomerAllowedList($dbserver);
|
||||||
|
|
||||||
|
$description = $sql_root[$dbserver]['caption'] ?? "unknown";
|
||||||
|
$mysql_host = $sql_root[$dbserver]['host'] ?? "unknown";
|
||||||
unset($sql_root[$dbserver]);
|
unset($sql_root[$dbserver]);
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] removed database server '" . $description . "' (" . $mysql_host . ")");
|
||||||
|
|
||||||
$this->generateNewUserData($sql, $sql_root);
|
$this->generateNewUserData($sql, $sql_root);
|
||||||
return $this->response(['true']);
|
return $this->response(['true']);
|
||||||
}
|
}
|
||||||
@@ -287,14 +294,14 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional the number of the mysql server (either id or dbserver must be set)
|
* optional the number of the mysql server (either id or dbserver must be set)
|
||||||
*
|
*
|
||||||
* @access admin, customer
|
* @access admin, customer
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function get()
|
public function get()
|
||||||
{
|
{
|
||||||
$id = (int) $this->getParam('id', true, -1);
|
$id = (int)$this->getParam('id', true, -1);
|
||||||
$dn_optional = $id >= 0;
|
$dn_optional = $id >= 0;
|
||||||
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
|
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
|
||||||
$dbserver = $id >= 0 ? $id : $dbserver;
|
$dbserver = $id >= 0 ? $id : $dbserver;
|
||||||
|
|
||||||
$sql_root = [];
|
$sql_root = [];
|
||||||
@@ -317,6 +324,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
unset($sql_root[$dbserver]['password']);
|
unset($sql_root[$dbserver]['password']);
|
||||||
$sql_root[$dbserver]['id'] = $dbserver;
|
$sql_root[$dbserver]['id'] = $dbserver;
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get database-server '" . $sql_root[$dbserver]['caption'] . "'");
|
||||||
return $this->response($sql_root[$dbserver]);
|
return $this->response($sql_root[$dbserver]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,16 +355,16 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional, test connection with given credentials, default is true (yes)
|
* optional, test connection with given credentials, default is true (yes)
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
$this->validateAccess();
|
$this->validateAccess();
|
||||||
|
|
||||||
$id = (int) $this->getParam('id', true, -1);
|
$id = (int)$this->getParam('id', true, -1);
|
||||||
$dn_optional = $id >= 0;
|
$dn_optional = $id >= 0;
|
||||||
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
|
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
|
||||||
$dbserver = $id >= 0 ? $id : $dbserver;
|
$dbserver = $id >= 0 ? $id : $dbserver;
|
||||||
|
|
||||||
$sql_root = [];
|
$sql_root = [];
|
||||||
@@ -417,7 +425,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
);
|
);
|
||||||
if (!empty($mysql_ca)) {
|
if (!empty($mysql_ca)) {
|
||||||
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
||||||
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool) $mysql_verifycert;
|
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool)$mysql_verifycert;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
||||||
@@ -448,6 +456,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
$this->addDatabaseFromCustomerAllowedList($dbserver);
|
$this->addDatabaseFromCustomerAllowedList($dbserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] edited database server '" . $description . "' (" . $mysql_host . ")");
|
||||||
|
|
||||||
return $this->response(['true']);
|
return $this->response(['true']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +482,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
WHERE `dbserver` = :dbserver
|
WHERE `dbserver` = :dbserver
|
||||||
");
|
");
|
||||||
$result = Database::pexecute_first($result_stmt, ['dbserver' => $dbserver], true, true);
|
$result = Database::pexecute_first($result_stmt, ['dbserver' => $dbserver], true, true);
|
||||||
return (int) $result['num_dbs'];
|
return (int)$result['num_dbs'];
|
||||||
} else {
|
} else {
|
||||||
$dbserver = $this->getParam('mysql_server');
|
$dbserver = $this->getParam('mysql_server');
|
||||||
$customer_ids = $this->getAllowedCustomerIds();
|
$customer_ids = $this->getAllowedCustomerIds();
|
||||||
@@ -516,7 +526,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
`allowed_mysqlserver` = :am WHERE `customerid` = :cid
|
`allowed_mysqlserver` = :am WHERE `customerid` = :cid
|
||||||
");
|
");
|
||||||
while ($customer = $sel_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($customer = $sel_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$allowed_mysqls = json_decode(($customer['allowed_mysqlserver'] ?? '[]'), true);
|
$allowed_mysqls = json_decode(($customer['allowed_mysqlserver'] ?: '[]'), true);
|
||||||
if (!in_array($dbserver, $allowed_mysqls)) {
|
if (!in_array($dbserver, $allowed_mysqls)) {
|
||||||
$allowed_mysqls[] = $dbserver;
|
$allowed_mysqls[] = $dbserver;
|
||||||
$allowed_mysqls = json_encode($allowed_mysqls);
|
$allowed_mysqls = json_encode($allowed_mysqls);
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
$this->mailer()->clearAddresses();
|
$this->mailer()->clearAddresses();
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] added mysql-database '" . $username . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added mysql-database '" . $username . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Mysqls.get', [
|
$result = $this->apiCall('Mysqls.get', [
|
||||||
'dbname' => $username,
|
'dbname' => $username,
|
||||||
@@ -299,7 +299,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
$mbdata = $mbdata_stmt->fetch(PDO::FETCH_ASSOC);
|
$mbdata = $mbdata_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
Database::needRoot(false);
|
Database::needRoot(false);
|
||||||
$result['size'] = $mbdata['MB'] ?? 0;
|
$result['size'] = $mbdata['MB'] ?? 0;
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get database '" . $result['databasename'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get database '" . $result['databasename'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "dbname '" . $dbname . "'");
|
$key = ($id > 0 ? "id #" . $id : "dbname '" . $dbname . "'");
|
||||||
@@ -388,7 +388,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] updated mysql-database '" . $result['databasename'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated mysql-database '" . $result['databasename'] . "'");
|
||||||
$result = $this->apiCall('Mysqls.get', [
|
$result = $this->apiCall('Mysqls.get', [
|
||||||
'dbname' => $result['databasename']
|
'dbname' => $result['databasename']
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list php-configs");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list php-configs");
|
||||||
|
|
||||||
$with_subdomains = $this->getBoolParam('with_subdomains', true, false);
|
$with_subdomains = $this->getBoolParam('with_subdomains', true, false);
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
@@ -392,7 +392,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
$ins_data['id'] = Database::lastInsertId();
|
$ins_data['id'] = Database::lastInsertId();
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('PhpSettings.get', [
|
$result = $this->apiCall('PhpSettings.get', [
|
||||||
'id' => $ins_data['id']
|
'id' => $ins_data['id']
|
||||||
@@ -629,7 +629,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
Database::pexecute($upd_stmt, $upd_data, true, true);
|
Database::pexecute($upd_stmt, $upd_data, true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('PhpSettings.get', [
|
$result = $this->apiCall('PhpSettings.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
@@ -686,7 +686,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
|||||||
@@ -62,11 +62,13 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, overwrites path value with an URL to generate a redirect, alternatively use the path
|
* optional, overwrites path value with an URL to generate a redirect, alternatively use the path
|
||||||
* parameter also for URLs
|
* parameter also for URLs
|
||||||
* @param int $openbasedir_path
|
* @param int $openbasedir_path
|
||||||
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
* optional, either 0 for domains-docroot [default], 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, php-settings-id, if empty the $domain value is used
|
* optional, php-settings-id, if empty the $domain value is used
|
||||||
* @param int $redirectcode
|
* @param int $redirectcode
|
||||||
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
|
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
|
||||||
|
* @param int $speciallogfile
|
||||||
|
* optional, whether to create an exclusive web-logfile for this domain (1) or not (0) or inherit value from parentdomain (2, default)
|
||||||
* @param bool $sslenabled
|
* @param bool $sslenabled
|
||||||
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
||||||
* 1 (true)
|
* 1 (true)
|
||||||
@@ -104,9 +106,10 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$aliasdomain = $this->getParam('alias', true, 0);
|
$aliasdomain = $this->getParam('alias', true, 0);
|
||||||
$path = $this->getParam('path', true, '');
|
$path = $this->getParam('path', true, '');
|
||||||
$url = $this->getParam('url', true, '');
|
$url = $this->getParam('url', true, '');
|
||||||
$openbasedir_path = $this->getParam('openbasedir_path', true, 1);
|
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, 0);
|
$phpsettingid = $this->getParam('phpsettingid', true, 0);
|
||||||
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
|
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
|
||||||
|
$speciallogfile = intval($this->getParam('speciallogfile', true, 2));
|
||||||
$isemaildomain = $this->getParam('isemaildomain', true, 0);
|
$isemaildomain = $this->getParam('isemaildomain', true, 0);
|
||||||
if (Settings::Get('system.use_ssl')) {
|
if (Settings::Get('system.use_ssl')) {
|
||||||
$sslenabled = $this->getBoolParam('sslenabled', true, 1);
|
$sslenabled = $this->getBoolParam('sslenabled', true, 1);
|
||||||
@@ -229,6 +232,9 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
} elseif ($completedomain_check && strtolower($completedomain_check['domain']) == strtolower($completedomain)) {
|
} elseif ($completedomain_check && strtolower($completedomain_check['domain']) == strtolower($completedomain)) {
|
||||||
// the domain does already exist as main-domain
|
// the domain does already exist as main-domain
|
||||||
Response::standardError('domainexistalready', $completedomain, true);
|
Response::standardError('domainexistalready', $completedomain, true);
|
||||||
|
} elseif ((int)$domain_check['deactivated'] == 1) {
|
||||||
|
// main domain is deactivated
|
||||||
|
Response::standardError('maindomaindeactivated', $domain, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if allowed, check for 'is email domain'-flag
|
// if allowed, check for 'is email domain'-flag
|
||||||
@@ -273,6 +279,11 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$ssl_redirect = 2;
|
$ssl_redirect = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate speciallogfile value
|
||||||
|
if ($speciallogfile < 0 || $speciallogfile > 2) {
|
||||||
|
$speciallogfile = 2; // inherit from parent-domain
|
||||||
|
}
|
||||||
|
|
||||||
// get the phpsettingid from parentdomain, #107
|
// get the phpsettingid from parentdomain, #107
|
||||||
$phpsid_stmt = Database::prepare("
|
$phpsid_stmt = Database::prepare("
|
||||||
SELECT `phpsettingid` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `id` = :id
|
SELECT `phpsettingid` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `id` = :id
|
||||||
@@ -351,7 +362,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
"openbasedir" => $domain_check['openbasedir'],
|
"openbasedir" => $domain_check['openbasedir'],
|
||||||
"openbasedir_path" => $openbasedir_path,
|
"openbasedir_path" => $openbasedir_path,
|
||||||
"phpenabled" => $domain_check['phpenabled'],
|
"phpenabled" => $domain_check['phpenabled'],
|
||||||
"speciallogfile" => $domain_check['speciallogfile'],
|
"speciallogfile" => $speciallogfile == 2 ? $domain_check['speciallogfile'] : $speciallogfile,
|
||||||
"specialsettings" => $domain_check['specialsettings'],
|
"specialsettings" => $domain_check['specialsettings'],
|
||||||
"ssl_specialsettings" => $domain_check['ssl_specialsettings'],
|
"ssl_specialsettings" => $domain_check['ssl_specialsettings'],
|
||||||
"include_specialsettings" => $domain_check['include_specialsettings'],
|
"include_specialsettings" => $domain_check['include_specialsettings'],
|
||||||
@@ -486,7 +497,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
||||||
}
|
}
|
||||||
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get subdomain '" . $result['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get subdomain '" . $result['domain'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
||||||
@@ -588,6 +599,11 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, php-settings-id, if empty the $domain value is used
|
* optional, php-settings-id, if empty the $domain value is used
|
||||||
* @param int $redirectcode
|
* @param int $redirectcode
|
||||||
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
|
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
|
||||||
|
* @param bool $speciallogfile
|
||||||
|
* optional, whether to create an exclusive web-logfile for this domain
|
||||||
|
* @param bool $speciallogverified
|
||||||
|
* optional, when setting $speciallogfile to false, this needs to be set to true to confirm the action,
|
||||||
|
* default 0 (false)
|
||||||
* @param bool $sslenabled
|
* @param bool $sslenabled
|
||||||
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
||||||
* 1 (true)
|
* 1 (true)
|
||||||
@@ -645,6 +661,8 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$openbasedir_path = $this->getParam('openbasedir_path', true, $result['openbasedir_path']);
|
$openbasedir_path = $this->getParam('openbasedir_path', true, $result['openbasedir_path']);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
||||||
$redirectcode = $this->getParam('redirectcode', true, Domain::getDomainRedirectId($id));
|
$redirectcode = $this->getParam('redirectcode', true, Domain::getDomainRedirectId($id));
|
||||||
|
$speciallogfile = $this->getBoolParam('speciallogfile', true, $result['speciallogfile']);
|
||||||
|
$speciallogverified = $this->getBoolParam('speciallogverified', true, 0);
|
||||||
if (Settings::Get('system.use_ssl')) {
|
if (Settings::Get('system.use_ssl')) {
|
||||||
$sslenabled = $this->getBoolParam('sslenabled', true, $result['ssl_enabled']);
|
$sslenabled = $this->getBoolParam('sslenabled', true, $result['ssl_enabled']);
|
||||||
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, $result['ssl_redirect']);
|
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, $result['ssl_redirect']);
|
||||||
@@ -754,6 +772,10 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$ssl_redirect = 2;
|
$ssl_redirect = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($speciallogfile != $result['speciallogfile'] && $speciallogverified != '1') {
|
||||||
|
$speciallogfile = $result['speciallogfile'];
|
||||||
|
}
|
||||||
|
|
||||||
// is-email-domain flag changed - remove mail accounts and mail-addresses
|
// is-email-domain flag changed - remove mail accounts and mail-addresses
|
||||||
if (($result['isemaildomain'] == '1') && $isemaildomain == '0') {
|
if (($result['isemaildomain'] == '1') && $isemaildomain == '0') {
|
||||||
$params = [
|
$params = [
|
||||||
@@ -786,7 +808,21 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
Domain::updateRedirectOfDomain($id, $redirectcode);
|
Domain::updateRedirectOfDomain($id, $redirectcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($path != $result['documentroot'] || $isemaildomain != $result['isemaildomain'] || $wwwserveralias != $result['wwwserveralias'] || $iswildcarddomain != $result['iswildcarddomain'] || $aliasdomain != (int)$result['aliasdomain'] || $openbasedir_path != $result['openbasedir_path'] || $ssl_redirect != $result['ssl_redirect'] || $letsencrypt != $result['letsencrypt'] || $hsts_maxage != $result['hsts'] || $hsts_sub != $result['hsts_sub'] || $hsts_preload != $result['hsts_preload'] || $phpsettingid != $result['phpsettingid'] || $http2 != $result['http2']) {
|
if ($path != $result['documentroot']
|
||||||
|
|| $isemaildomain != $result['isemaildomain']
|
||||||
|
|| $wwwserveralias != $result['wwwserveralias']
|
||||||
|
|| $iswildcarddomain != $result['iswildcarddomain']
|
||||||
|
|| $aliasdomain != (int)$result['aliasdomain']
|
||||||
|
|| $openbasedir_path != $result['openbasedir_path']
|
||||||
|
|| $ssl_redirect != $result['ssl_redirect']
|
||||||
|
|| $letsencrypt != $result['letsencrypt']
|
||||||
|
|| $hsts_maxage != $result['hsts']
|
||||||
|
|| $hsts_sub != $result['hsts_sub']
|
||||||
|
|| $hsts_preload != $result['hsts_preload']
|
||||||
|
|| $phpsettingid != $result['phpsettingid']
|
||||||
|
|| $http2 != $result['http2']
|
||||||
|
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|
||||||
|
) {
|
||||||
$stmt = Database::prepare("
|
$stmt = Database::prepare("
|
||||||
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
|
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
|
||||||
`documentroot` = :documentroot,
|
`documentroot` = :documentroot,
|
||||||
@@ -802,7 +838,8 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
`hsts` = :hsts,
|
`hsts` = :hsts,
|
||||||
`hsts_sub` = :hsts_sub,
|
`hsts_sub` = :hsts_sub,
|
||||||
`hsts_preload` = :hsts_preload,
|
`hsts_preload` = :hsts_preload,
|
||||||
`phpsettingid` = :phpsettingid
|
`phpsettingid` = :phpsettingid,
|
||||||
|
`speciallogfile` = :speciallogfile
|
||||||
WHERE `customerid`= :customerid AND `id`= :id
|
WHERE `customerid`= :customerid AND `id`= :id
|
||||||
");
|
");
|
||||||
$params = [
|
$params = [
|
||||||
@@ -820,6 +857,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
"hsts_sub" => $hsts_sub,
|
"hsts_sub" => $hsts_sub,
|
||||||
"hsts_preload" => $hsts_preload,
|
"hsts_preload" => $hsts_preload,
|
||||||
"phpsettingid" => $phpsettingid,
|
"phpsettingid" => $phpsettingid,
|
||||||
|
"speciallogfile" => $speciallogfile,
|
||||||
"customerid" => $customer['customerid'],
|
"customerid" => $customer['customerid'],
|
||||||
"id" => $id
|
"id" => $id
|
||||||
];
|
];
|
||||||
@@ -856,7 +894,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_DNS);
|
Cronjob::inserttask(TaskId::REBUILD_DNS);
|
||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'");
|
||||||
}
|
}
|
||||||
$result = $this->apiCall('SubDomains.get', [
|
$result = $this->apiCall('SubDomains.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
@@ -865,7 +903,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lists all subdomain entries
|
* lists all customer domain/subdomain entries
|
||||||
*
|
*
|
||||||
* @param bool $with_ips
|
* @param bool $with_ips
|
||||||
* optional, default true
|
* optional, default true
|
||||||
@@ -910,17 +948,12 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$custom_list_result = $_custom_list_result['list'];
|
$custom_list_result = $_custom_list_result['list'];
|
||||||
}
|
}
|
||||||
$customer_ids = [];
|
$customer_ids = [];
|
||||||
$customer_stdsubs = [];
|
|
||||||
foreach ($custom_list_result as $customer) {
|
foreach ($custom_list_result as $customer) {
|
||||||
$customer_ids[] = $customer['customerid'];
|
$customer_ids[] = $customer['customerid'];
|
||||||
$customer_stdsubs[$customer['customerid']] = $customer['standardsubdomain'];
|
|
||||||
}
|
}
|
||||||
if (empty($customer_ids)) {
|
if (empty($customer_ids)) {
|
||||||
throw new Exception("Required resource unsatisfied.", 405);
|
throw new Exception("Required resource unsatisfied.", 405);
|
||||||
}
|
}
|
||||||
if (empty($customer_stdsubs)) {
|
|
||||||
throw new Exception("Required resource unsatisfied.", 405);
|
|
||||||
}
|
|
||||||
|
|
||||||
$select_fields = [
|
$select_fields = [
|
||||||
'`d`.*'
|
'`d`.*'
|
||||||
@@ -932,9 +965,6 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$customer_ids = [
|
$customer_ids = [
|
||||||
$this->getUserDetail('customerid')
|
$this->getUserDetail('customerid')
|
||||||
];
|
];
|
||||||
$customer_stdsubs = [
|
|
||||||
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
|
|
||||||
];
|
|
||||||
|
|
||||||
$select_fields = [
|
$select_fields = [
|
||||||
'`d`.`id`',
|
'`d`.`id`',
|
||||||
@@ -949,7 +979,8 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
'`d`.`parentdomainid`',
|
'`d`.`parentdomainid`',
|
||||||
'`d`.`letsencrypt`',
|
'`d`.`letsencrypt`',
|
||||||
'`d`.`registration_date`',
|
'`d`.`registration_date`',
|
||||||
'`d`.`termination_date`'
|
'`d`.`termination_date`',
|
||||||
|
'`d`.`deactivated`'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
@@ -963,7 +994,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON `pd`.`id`=`d`.`parentdomainid`
|
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON `pd`.`id`=`d`.`parentdomainid`
|
||||||
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
||||||
AND `d`.`email_only` = '0'
|
AND `d`.`email_only` = '0'
|
||||||
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit());
|
" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit());
|
||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
Database::pexecute($domains_stmt, $query_fields, true, true);
|
Database::pexecute($domains_stmt, $query_fields, true, true);
|
||||||
@@ -1063,17 +1094,19 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
|
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// prepare select statement
|
if (!empty($customer_ids)) {
|
||||||
$domains_stmt = Database::prepare("
|
// prepare select statement
|
||||||
SELECT COUNT(*) as num_subdom
|
$domains_stmt = Database::prepare("
|
||||||
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
SELECT COUNT(*) as num_subdom
|
||||||
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
||||||
AND `d`.`email_only` = '0'
|
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
||||||
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")
|
AND `d`.`email_only` = '0'
|
||||||
");
|
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")
|
||||||
$result = Database::pexecute_first($domains_stmt, null, true, true);
|
");
|
||||||
if ($result) {
|
$result = Database::pexecute_first($domains_stmt, null, true, true);
|
||||||
return $this->response($result['num_subdom']);
|
if ($result) {
|
||||||
|
return $this->response($result['num_subdom']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $this->response(0);
|
return $this->response(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class SysLog extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list log-entries");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list log-entries");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ class Traffic extends ApiCommand implements ResourceEntity
|
|||||||
$row['mail'] *= 1024;
|
$row['mail'] *= 1024;
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list traffic");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list traffic");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
|
|||||||
@@ -112,11 +112,11 @@ class FroxlorRPC
|
|||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private static function validateAllowedFrom(array $allowed_from, string $remote_addr): bool
|
public static function validateAllowedFrom(array $allowed_from, string $remote_addr): bool
|
||||||
{
|
{
|
||||||
// shorten IP for comparison
|
// shorten IP for comparison
|
||||||
$remote_addr = inet_ntop(inet_pton($remote_addr));
|
$remote_addr = inet_ntop(inet_pton($remote_addr));
|
||||||
// check for diret matches
|
// check for direct matches
|
||||||
if (in_array($remote_addr, $allowed_from)) {
|
if (in_array($remote_addr, $allowed_from)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
53
lib/Froxlor/Backup/Backup.php
Normal file
53
lib/Froxlor/Backup/Backup.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Backup;
|
||||||
|
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
class Backup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* returns an array of existing backup-storages
|
||||||
|
* in our database for the settings-array
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getBackupStorages(): array
|
||||||
|
{
|
||||||
|
$storages_array = [
|
||||||
|
0 => lng('backup.storage_none')
|
||||||
|
];
|
||||||
|
// get all storages
|
||||||
|
$result_stmt = Database::query("SELECT id, type, description FROM `" . TABLE_PANEL_BACKUP_STORAGES . "` ORDER BY type, description");
|
||||||
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
if (!isset($storages_array[$row['id']]) && !in_array($row['id'], $storages_array)) {
|
||||||
|
$storages_array[$row['id']] = "[" . $row['type'] . "] " . html_entity_decode($row['description']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $storages_array;
|
||||||
|
}
|
||||||
|
}
|
||||||
102
lib/Froxlor/Backup/Storages/Ftp.php
Normal file
102
lib/Froxlor/Backup/Storages/Ftp.php
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Backup\Storages;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
|
||||||
|
class Ftp extends Storage
|
||||||
|
{
|
||||||
|
private $ftp_conn = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function init(): bool
|
||||||
|
{
|
||||||
|
$hostname = $this->sData['storage']['hostname'] ?? '';
|
||||||
|
$username = $this->sData['storage']['username'] ?? '';
|
||||||
|
$password = $this->sData['storage']['password'] ?? '';
|
||||||
|
if (!empty($hostname) && !empty($username) && !empty($password)) {
|
||||||
|
$tmp = explode(":", $hostname);
|
||||||
|
$hostname = $tmp[0];
|
||||||
|
$port = $tmp[1] ?? 21;
|
||||||
|
$this->ftp_conn = ftp_connect($hostname, $port);
|
||||||
|
if ($this->ftp_conn === false) {
|
||||||
|
throw new Exception('Unable to connect to ftp-server "' . $hostname . ':' . $port . '"');
|
||||||
|
}
|
||||||
|
if (!ftp_login($this->ftp_conn, $username, $password)) {
|
||||||
|
throw new Exception('Unable to login to ftp-server "' . $hostname . ':' . $port . '"');
|
||||||
|
}
|
||||||
|
return $this->changeToCorrectDirectory();
|
||||||
|
}
|
||||||
|
throw new Exception('Empty hostname for FTP backup storage');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move/Upload file from tmp-source-directory. The file should be moved or deleted afterward.
|
||||||
|
* Must return the (relative) path including filename to the backup.
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @param string $tmp_source_directory
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function putFile(string $filename, string $tmp_source_directory): string
|
||||||
|
{
|
||||||
|
$source = FileDir::makeCorrectFile($tmp_source_directory . "/" . $filename);
|
||||||
|
if (file_exists($source) && ftp_size($this->ftp_conn, $filename) == -1) {
|
||||||
|
if (ftp_put($this->ftp_conn, $filename, $source, FTP_BINARY)) {
|
||||||
|
return FileDir::makeCorrectFile($this->getDestinationDirectory() . '/' . $filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $filename
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function rmFile(string $filename): bool
|
||||||
|
{
|
||||||
|
$target = basename($filename);
|
||||||
|
if (ftp_size($this->ftp_conn, $target) >= 0) {
|
||||||
|
return ftp_delete($this->ftp_conn, $target);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function shutdown(): bool
|
||||||
|
{
|
||||||
|
return ftp_close($this->ftp_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function changeToCorrectDirectory(): bool
|
||||||
|
{
|
||||||
|
$dirs = explode("/", $this->getDestinationDirectory());
|
||||||
|
array_shift($dirs);
|
||||||
|
if (count($dirs) > 0 && !empty($dirs[0])) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (empty($dir)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!@ftp_chdir($this->ftp_conn, $dir)) {
|
||||||
|
ftp_mkdir($this->ftp_conn, $dir);
|
||||||
|
ftp_chmod($this->ftp_conn, 0700, $dir);
|
||||||
|
ftp_chdir($this->ftp_conn, $dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return ftp_chdir($this->ftp_conn, "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
64
lib/Froxlor/Backup/Storages/Local.php
Normal file
64
lib/Froxlor/Backup/Storages/Local.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Backup\Storages;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
|
||||||
|
class Local extends Storage
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function init(): bool
|
||||||
|
{
|
||||||
|
// create destination_path
|
||||||
|
if (!file_exists($this->getDestinationDirectory())) {
|
||||||
|
return mkdir($this->getDestinationDirectory(), 0700, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move/Upload file from tmp-source-directory. The file should be moved or deleted afterward.
|
||||||
|
* Must return the (relative) path including filename to the backup.
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @param string $tmp_source_directory
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function putFile(string $filename, string $tmp_source_directory): string
|
||||||
|
{
|
||||||
|
$source = FileDir::makeCorrectFile($tmp_source_directory . "/" . $filename);
|
||||||
|
$target = FileDir::makeCorrectFile($this->getDestinationDirectory() . "/" . $filename);
|
||||||
|
if (file_exists($source) && !file_exists($target)) {
|
||||||
|
rename($source, $target);
|
||||||
|
return $target;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $filename
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function rmFile(string $filename): bool
|
||||||
|
{
|
||||||
|
$target = FileDir::makeCorrectFile($this->getDestinationDirectory() . "/" . $filename);
|
||||||
|
if (file_exists($target)) {
|
||||||
|
return @unlink($target);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function shutdown(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
lib/Froxlor/Backup/Storages/Rsync.php
Normal file
45
lib/Froxlor/Backup/Storages/Rsync.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Backup\Storages;
|
||||||
|
|
||||||
|
class Rsync extends Storage
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function init(): bool
|
||||||
|
{
|
||||||
|
// TODO: Implement init() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move/Upload file from tmp-source-directory. The file should be moved or deleted afterward.
|
||||||
|
* Must return the (relative) path including filename to the backup.
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @param string $tmp_source_directory
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function putFile(string $filename, string $tmp_source_directory): string
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $filename
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function rmFile(string $filename): bool
|
||||||
|
{
|
||||||
|
// TODO: Implement removeOld() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function shutdown(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
lib/Froxlor/Backup/Storages/S3.php
Normal file
45
lib/Froxlor/Backup/Storages/S3.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Backup\Storages;
|
||||||
|
|
||||||
|
class S3 extends Storage
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function init(): bool
|
||||||
|
{
|
||||||
|
// TODO: Implement init() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move/Upload file from tmp-source-directory. The file should be moved or deleted afterward.
|
||||||
|
* Must return the (relative) path including filename to the backup.
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @param string $tmp_source_directory
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function putFile(string $filename, string $tmp_source_directory): string
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $filename
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function rmFile(string $filename): bool
|
||||||
|
{
|
||||||
|
// TODO: Implement removeOld() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function shutdown(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
lib/Froxlor/Backup/Storages/Sftp.php
Normal file
45
lib/Froxlor/Backup/Storages/Sftp.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Backup\Storages;
|
||||||
|
|
||||||
|
class Sftp extends Storage
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function init(): bool
|
||||||
|
{
|
||||||
|
// TODO: Implement init() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move/Upload file from tmp-source-directory. The file should be moved or deleted afterward.
|
||||||
|
* Must return the (relative) path including filename to the backup.
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @param string $tmp_source_directory
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function putFile(string $filename, string $tmp_source_directory): string
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $filename
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function rmFile(string $filename): bool
|
||||||
|
{
|
||||||
|
// TODO: Implement removeOld() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function shutdown(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
281
lib/Froxlor/Backup/Storages/Storage.php
Normal file
281
lib/Froxlor/Backup/Storages/Storage.php
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Backup\Storages;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
|
||||||
|
abstract class Storage
|
||||||
|
{
|
||||||
|
private string $tmpDirectory;
|
||||||
|
protected array $sData;
|
||||||
|
|
||||||
|
protected array $filesToStore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function __construct(array $storage_data)
|
||||||
|
{
|
||||||
|
$this->sData = $storage_data;
|
||||||
|
$this->tmpDirectory = FileDir::makeCorrectDir(sys_get_temp_dir() . '/backup-' . $this->sData['loginname']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate sData, open connection to target storage, etc.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
abstract public function init(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect / clean up connection if needed
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
abstract public function shutdown(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepare files to back up (e.g. create archive or similar) and fill $filesToStore
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function prepareFiles(): void
|
||||||
|
{
|
||||||
|
$this->filesToStore = [];
|
||||||
|
|
||||||
|
$tmpdir = FileDir::makeCorrectDir($this->tmpDirectory . '/.tmp/');
|
||||||
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
||||||
|
|
||||||
|
// create archive of web, mail and database data
|
||||||
|
$this->prepareWebData();
|
||||||
|
$this->prepareDatabaseData();
|
||||||
|
$this->prepareMailData();
|
||||||
|
|
||||||
|
// create json-info-file
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function prepareWebData(): void
|
||||||
|
{
|
||||||
|
$tmpdir = FileDir::makeCorrectDir($this->tmpDirectory . '/.tmp/web');
|
||||||
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
||||||
|
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/' . $this->sData['loginname'] . '-web.tar.gz')) . ' -C ' . escapeshellarg($this->sData['documentroot']) . ' .');
|
||||||
|
$this->filesToStore[] = FileDir::makeCorrectFile($tmpdir . '/' . $this->sData['loginname'] . '-web.tar.gz');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function prepareDatabaseData(): void
|
||||||
|
{
|
||||||
|
$tmpdir = FileDir::makeCorrectDir($this->tmpDirectory . '/.tmp/mysql');
|
||||||
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
||||||
|
|
||||||
|
// get all customer database-names
|
||||||
|
$sel_stmt = Database::prepare("
|
||||||
|
SELECT `databasename`, `dbserver` FROM `" . TABLE_PANEL_DATABASES . "`
|
||||||
|
WHERE `customerid` = :cid ORDER BY `dbserver`
|
||||||
|
");
|
||||||
|
Database::pexecute($sel_stmt, [
|
||||||
|
'cid' => $this->sData['customerid']
|
||||||
|
]);
|
||||||
|
|
||||||
|
$has_dbs = false;
|
||||||
|
$current_dbserver = -1;
|
||||||
|
while ($row = $sel_stmt->fetch()) {
|
||||||
|
// Get sql_root data for the specific database-server the database resides on
|
||||||
|
if ($current_dbserver != $row['dbserver']) {
|
||||||
|
Database::needRoot(true, $row['dbserver']);
|
||||||
|
Database::needSqlData();
|
||||||
|
$sql_root = Database::getSqlData();
|
||||||
|
Database::needRoot(false);
|
||||||
|
// create temporary mysql-defaults file for the connection-credentials/details
|
||||||
|
$mysqlcnf_file = tempnam("/tmp", "frx");
|
||||||
|
$mysqlcnf = "[mysqldump]\npassword=" . $sql_root['passwd'] . "\nhost=" . $sql_root['host'] . "\n";
|
||||||
|
if (!empty($sql_root['port'])) {
|
||||||
|
$mysqlcnf .= "port=" . $sql_root['port'] . "\n";
|
||||||
|
} elseif (!empty($sql_root['socket'])) {
|
||||||
|
$mysqlcnf .= "socket=" . $sql_root['socket'] . "\n";
|
||||||
|
}
|
||||||
|
file_put_contents($mysqlcnf_file, $mysqlcnf);
|
||||||
|
}
|
||||||
|
$bool_false = false;
|
||||||
|
FileDir::safe_exec('mysqldump --defaults-file=' . escapeshellarg($mysqlcnf_file) . ' -u ' . escapeshellarg($sql_root['user']) . ' ' . $row['databasename'] . ' > ' . FileDir::makeCorrectFile($tmpdir . '/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'), $bool_false, [
|
||||||
|
'>'
|
||||||
|
]);
|
||||||
|
$has_dbs = true;
|
||||||
|
$current_dbserver = $row['dbserver'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($has_dbs) {
|
||||||
|
$this->filesToStore[] = $tmpdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@file_exists($mysqlcnf_file)) {
|
||||||
|
@unlink($mysqlcnf_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareMailData(): void
|
||||||
|
{
|
||||||
|
$tmpdir = FileDir::makeCorrectDir($this->tmpDirectory . '/.tmp/mail');
|
||||||
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
||||||
|
|
||||||
|
// get all customer mail-accounts
|
||||||
|
$sel_stmt = Database::prepare("
|
||||||
|
SELECT `homedir`, `maildir` FROM `" . TABLE_MAIL_USERS . "`
|
||||||
|
WHERE `customerid` = :cid
|
||||||
|
");
|
||||||
|
Database::pexecute($sel_stmt, [
|
||||||
|
'cid' => $this->sData['customerid']
|
||||||
|
]);
|
||||||
|
|
||||||
|
$tar_file_list = "";
|
||||||
|
$mail_homedir = "";
|
||||||
|
while ($row = $sel_stmt->fetch()) {
|
||||||
|
$tar_file_list .= escapeshellarg("./" . $row['maildir']) . " ";
|
||||||
|
if (empty($mail_homedir)) {
|
||||||
|
// this should be equal for all entries
|
||||||
|
$mail_homedir = $row['homedir'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($tar_file_list)) {
|
||||||
|
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/' . $this->sData['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
||||||
|
$this->filesToStore[] = FileDir::makeCorrectFile($tmpdir . '/' . $this->sData['loginname'] . '-mail.tar.gz');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move/Upload file from tmp-source-directory. The file should be moved or deleted afterward.
|
||||||
|
* Must return the (relative) path including filename to the backup.
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @param string $tmp_source_directory
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract protected function putFile(string $filename, string $tmp_source_directory): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $filename
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
abstract protected function rmFile(string $filename): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function removeOld(): bool
|
||||||
|
{
|
||||||
|
// retention in days
|
||||||
|
$retention = $this->sData['storage']['retention'] ?? 3;
|
||||||
|
// keep date
|
||||||
|
$keepDate = new \DateTime();
|
||||||
|
$keepDate->setTime(0, 0, 0, 1);
|
||||||
|
// subtract retention days
|
||||||
|
$keepDate->sub(new \DateInterval('P' . $retention . 'D'));
|
||||||
|
// select target backups to remove for this storage-id and customer
|
||||||
|
$sel_stmt = Database::prepare("
|
||||||
|
SELECT * FROM `" . TABLE_PANEL_BACKUPS . "`
|
||||||
|
WHERE `created_at` < :keepdate
|
||||||
|
AND `storage_id` = :sid
|
||||||
|
AND `customerid` = :cid
|
||||||
|
");
|
||||||
|
Database::pexecute($sel_stmt, [
|
||||||
|
'keepdate' => $keepDate->format('U'),
|
||||||
|
'sid' => $this->sData['backup'],
|
||||||
|
'cid' => $this->sData['customerid']
|
||||||
|
]);
|
||||||
|
while ($oldBackup = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$this->rmFile($oldBackup['filename']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the storage configured destination path for all backups
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function getDestinationDirectory(): string
|
||||||
|
{
|
||||||
|
return FileDir::makeCorrectDir($this->sData['storage']['destination_path'] ?? "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create backup-archive/file from $filesToStore and call putFile()
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function createFromFiles(): bool
|
||||||
|
{
|
||||||
|
if (empty($this->filesToStore)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = FileDir::makeCorrectFile($this->tmpDirectory . "/backup-" . $this->sData['loginname'] . "-" . date('c') . ".tar.gz");
|
||||||
|
$tmpdir = FileDir::makeCorrectDir($this->tmpDirectory . '/.tmp/');
|
||||||
|
$create_export_tar_data = implode(" ", $this->filesToStore);
|
||||||
|
FileDir::safe_exec('chown -R ' . (int)$this->sData['guid'] . ':' . (int)$this->sData['guid'] . ' ' . escapeshellarg($tmpdir));
|
||||||
|
|
||||||
|
if (!empty($data['pgp_public_key'])) {
|
||||||
|
// pack all archives in tmp-dir to one archive and encrypt it with gpg
|
||||||
|
$recipient_file = FileDir::makeCorrectFile($this->tmpDirectory . '/' . $this->sData['loginname'] . '-recipients.gpg');
|
||||||
|
file_put_contents($recipient_file, $data['pgp_public_key']);
|
||||||
|
$return_value = [];
|
||||||
|
FileDir::safe_exec('tar cfz - -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data) . ' | gpg --encrypt --recipient-file ' . escapeshellarg($recipient_file) . ' --output ' . escapeshellarg($filename) . ' --trust-model always --batch --yes', $return_value, ['|']);
|
||||||
|
} else {
|
||||||
|
// pack all archives in tmp-dir to one archive
|
||||||
|
FileDir::safe_exec('tar cfz ' . escapeshellarg($filename) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine filesize (use stat locally here b/c files are possibly large and php's filesize() can't handle them)
|
||||||
|
$fileSizeOutput = FileDir::safe_exec('/usr/bin/stat -c "%s" ' . escapeshellarg($filename));
|
||||||
|
$fileSize = (int)array_shift($fileSizeOutput);
|
||||||
|
|
||||||
|
// add entry to database and upload/store file
|
||||||
|
|
||||||
|
FileDir::safe_exec('rm -rf ' . escapeshellarg($tmpdir));
|
||||||
|
$fileDest = $this->putFile(basename($filename), $this->tmpDirectory);
|
||||||
|
if (!empty($fileDest)) {
|
||||||
|
$this->addEntry($fileDest, $fileSize);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $filename
|
||||||
|
* @param int $fileSize
|
||||||
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function addEntry(string $filename, int $fileSize): void
|
||||||
|
{
|
||||||
|
$ins_stmt = Database::prepare("
|
||||||
|
INSERT INTO `" . TABLE_PANEL_BACKUPS . "` SET
|
||||||
|
`adminid` = :adminid,
|
||||||
|
`customerid` = :customerid,
|
||||||
|
`loginname` = :loginname,
|
||||||
|
`size` = :size,
|
||||||
|
`storage_id` = :sid,
|
||||||
|
`filename` = :filename,
|
||||||
|
`created_at` = UNIX_TIMESTAMP()
|
||||||
|
");
|
||||||
|
Database::pexecute($ins_stmt, [
|
||||||
|
'adminid' => $this->sData['adminid'],
|
||||||
|
'customerid' => $this->sData['customerid'],
|
||||||
|
'loginname' => $this->sData['loginname'],
|
||||||
|
'size' => $fileSize,
|
||||||
|
'sid' => $this->sData['backup'],
|
||||||
|
'filename' => $filename
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
lib/Froxlor/Backup/Storages/StorageFactory.php
Normal file
39
lib/Froxlor/Backup/Storages/StorageFactory.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Backup\Storages;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
|
||||||
|
class StorageFactory
|
||||||
|
{
|
||||||
|
public static function fromType(string $type, array $storage_data): Storage
|
||||||
|
{
|
||||||
|
$type = "\\Froxlor\\Backup\\Storages\\" . ucfirst($type);
|
||||||
|
return new $type($storage_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromStorageId(int $storage_id, array $user_data): Storage
|
||||||
|
{
|
||||||
|
$storage = self::readStorageData($storage_id);
|
||||||
|
$storage_data = $user_data;
|
||||||
|
$storage_data['storage'] = $storage;
|
||||||
|
return self::fromType($storage['type'], $storage_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private static function readStorageData(int $storage_id): array
|
||||||
|
{
|
||||||
|
$stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_BACKUP_STORAGES . "` WHERE `id` = :bid");
|
||||||
|
$storage = Database::pexecute_first($stmt, ['bid' => $storage_id]);
|
||||||
|
if (empty($storage)) {
|
||||||
|
throw new Exception("Invalid/empty backup-storage. Unable to continue");
|
||||||
|
}
|
||||||
|
return $storage;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -122,7 +122,7 @@ class CliCommand extends Command
|
|||||||
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
|
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
|
||||||
define('_CRON_UPDATE', 1);
|
define('_CRON_UPDATE', 1);
|
||||||
ob_start([
|
ob_start([
|
||||||
'this',
|
$this,
|
||||||
'cleanUpdateOutput'
|
'cleanUpdateOutput'
|
||||||
]);
|
]);
|
||||||
include_once Froxlor::getInstallDir() . '/install/updatesql.php';
|
include_once Froxlor::getInstallDir() . '/install/updatesql.php';
|
||||||
|
|||||||
178
lib/Froxlor/Cli/ConfigDiff.php
Normal file
178
lib/Froxlor/Cli/ConfigDiff.php
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
|
use Froxlor\Config\ConfigParser;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
final class ConfigDiff extends CliCommand
|
||||||
|
{
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this->setName('froxlor:config-diff')
|
||||||
|
->setDescription('Shows differences in config templates between OS versions')
|
||||||
|
->addArgument('from', InputArgument::OPTIONAL, 'OS version to compare against')
|
||||||
|
->addArgument('to', InputArgument::OPTIONAL, 'OS version to compare from')
|
||||||
|
->addOption('list', 'l', InputOption::VALUE_NONE, 'List all possible OS versions')
|
||||||
|
->addOption('diff-params', '', InputOption::VALUE_REQUIRED, 'Additional parameters for `diff`, e.g. --diff-params="--color=always"');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
require Froxlor::getInstallDir() . '/lib/functions.php';
|
||||||
|
|
||||||
|
$parsers = $versions = [];
|
||||||
|
foreach (glob(Froxlor::getInstallDir() . '/lib/configfiles/*.xml') as $config) {
|
||||||
|
$name = str_replace(".xml", "", strtolower(basename($config)));
|
||||||
|
$parser = new ConfigParser($config);
|
||||||
|
$versions[$name] = $parser->getCompleteDistroName();
|
||||||
|
$parsers[$name] = $parser;
|
||||||
|
}
|
||||||
|
asort($versions);
|
||||||
|
|
||||||
|
if ($input->getOption('list') === true) {
|
||||||
|
$output->writeln('The following OS version templates are available:');
|
||||||
|
foreach ($versions as $k => $v) {
|
||||||
|
$output->writeln(str_pad($k, 20) . $v);
|
||||||
|
}
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$input->hasArgument('from') || !array_key_exists($input->getArgument('from'), $versions)) {
|
||||||
|
$output->writeln('<error>Missing or invalid "from" argument.</error>');
|
||||||
|
$output->writeln('Available versions: ' . implode(', ', array_keys($versions)));
|
||||||
|
return self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$input->hasArgument('to') || !array_key_exists($input->getArgument('to'), $versions)) {
|
||||||
|
$output->writeln('<error>Missing or invalid "to" argument.</error>');
|
||||||
|
$output->writeln('Available versions: ' . implode(', ', array_keys($versions)));
|
||||||
|
return self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure diff is installed
|
||||||
|
$check_diff_installed = FileDir::safe_exec('which diff');
|
||||||
|
if (count($check_diff_installed) === 0) {
|
||||||
|
$output->writeln('<error>Unable to find "diff" installation on your system.</error>');
|
||||||
|
return self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parser_from = $parsers[$input->getArgument('from')];
|
||||||
|
$parser_to = $parsers[$input->getArgument('to')];
|
||||||
|
$tmp_from = tempnam(sys_get_temp_dir(), 'froxlor_config_diff_from');
|
||||||
|
$tmp_to = tempnam(sys_get_temp_dir(), 'froxlor_config_diff_to');
|
||||||
|
$files = [];
|
||||||
|
$titles_by_key = [];
|
||||||
|
|
||||||
|
// Aggregate content for each config file
|
||||||
|
foreach ([[$parser_from, 'from'], [$parser_to, 'to']] as $todo) {
|
||||||
|
foreach ($todo[0]->getServices() as $service_type => $service) {
|
||||||
|
foreach ($service->getDaemons() as $daemon_name => $daemon) {
|
||||||
|
foreach ($daemon->getConfig() as $instruction) {
|
||||||
|
if ($instruction['type'] !== 'file') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($instruction['subcommands'])) {
|
||||||
|
foreach ($instruction['subcommands'] as $subinstruction) {
|
||||||
|
if ($subinstruction['type'] !== 'file') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $subinstruction['content'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$content = $instruction['content'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($content)) {
|
||||||
|
throw new \Exception("Cannot find content for {$instruction['name']}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = "{$service_type}_{$daemon_name}_{$instruction['name']}";
|
||||||
|
$titles_by_key[$key] = "{$service->title} : {$daemon->title} : {$instruction['name']}";
|
||||||
|
if (!isset($files[$key])) {
|
||||||
|
$files[$key] = ['from' => '', 'to' => ''];
|
||||||
|
}
|
||||||
|
$files[$key][$todo[1]] = $this->filterContent($content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ksort($files);
|
||||||
|
|
||||||
|
$diff_params = '';
|
||||||
|
if ($input->hasOption('diff-params') && trim($input->getOption('diff-params')) !== '') {
|
||||||
|
$diff_params = trim($input->getOption('diff-params'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run diff on each file and output, if anything changed
|
||||||
|
foreach ($files as $file_key => $content) {
|
||||||
|
file_put_contents($tmp_from, $content['from']);
|
||||||
|
file_put_contents($tmp_to, $content['to']);
|
||||||
|
$diff_output = FileDir::safe_exec("{$check_diff_installed[0]} {$diff_params} {$tmp_from} {$tmp_to}");
|
||||||
|
|
||||||
|
if (count($diff_output) === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->writeln('<info># ' . $titles_by_key[$file_key] . '</info>');
|
||||||
|
$output->writeln(implode("\n", $diff_output) . "\n");
|
||||||
|
unset($diff_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove tmp files again
|
||||||
|
unlink($tmp_from);
|
||||||
|
unlink($tmp_to);
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function filterContent(string $content): string
|
||||||
|
{
|
||||||
|
$new_content = '';
|
||||||
|
|
||||||
|
foreach (explode("\n", $content) as $n) {
|
||||||
|
$n = trim($n);
|
||||||
|
if (!$n) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_starts_with($n, '#')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_content .= $n . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $new_content;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ final class ConfigServices extends CliCommand
|
|||||||
{
|
{
|
||||||
|
|
||||||
private $yes_to_all_supported = [
|
private $yes_to_all_supported = [
|
||||||
/* 'bookworm', */
|
'bookworm',
|
||||||
'bionic',
|
'bionic',
|
||||||
'bullseye',
|
'bullseye',
|
||||||
'buster',
|
'buster',
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ final class InstallCommand extends Command
|
|||||||
$_SERVER['SERVER_NAME'] = $host[0] ?? '';
|
$_SERVER['SERVER_NAME'] = $host[0] ?? '';
|
||||||
$ips = [];
|
$ips = [];
|
||||||
exec('hostname -I', $ips);
|
exec('hostname -I', $ips);
|
||||||
$ips = explode(" ", $ips[0]);
|
$ips = explode(" ", $ips[0] ?? "");
|
||||||
// ipv4 address?
|
// ipv4 address?
|
||||||
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ($ips[0] ?? '') : '';
|
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ($ips[0] ?? '') : '';
|
||||||
if (empty($_SERVER['SERVER_ADDR'])) {
|
if (empty($_SERVER['SERVER_ADDR'])) {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ final class MasterCron extends CliCommand
|
|||||||
$this->setDescription('Regulary perform tasks created by froxlor');
|
$this->setDescription('Regulary perform tasks created by froxlor');
|
||||||
$this->addArgument('job', InputArgument::IS_ARRAY, 'Job(s) to run');
|
$this->addArgument('job', InputArgument::IS_ARRAY, 'Job(s) to run');
|
||||||
$this->addOption('run-task', 'r', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Run a specific task [1 = re-generate configs, 4 = re-generate dns zones, 10 = re-set quotas, 99 = re-create cron.d-file]')
|
$this->addOption('run-task', 'r', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Run a specific task [1 = re-generate configs, 4 = re-generate dns zones, 10 = re-set quotas, 99 = re-create cron.d-file]')
|
||||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces re-generating of config-files (webserver, nameserver, etc.)')
|
->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces given job or, if none given, forces re-generating of config-files (webserver, nameserver, etc.)')
|
||||||
->addOption('debug', 'd', InputOption::VALUE_NONE, 'Output debug information about what is going on to STDOUT.')
|
->addOption('debug', 'd', InputOption::VALUE_NONE, 'Output debug information about what is going on to STDOUT.')
|
||||||
->addOption('no-fork', 'N', InputOption::VALUE_NONE, 'Do not fork to background (traffic cron only).');
|
->addOption('no-fork', 'N', InputOption::VALUE_NONE, 'Do not fork to background (traffic cron only).');
|
||||||
}
|
}
|
||||||
@@ -62,16 +62,22 @@ final class MasterCron extends CliCommand
|
|||||||
$result = self::SUCCESS;
|
$result = self::SUCCESS;
|
||||||
$result = $this->validateRequirements($input, $output);
|
$result = $this->validateRequirements($input, $output);
|
||||||
|
|
||||||
|
if ($result != self::SUCCESS) {
|
||||||
|
// requirements failed, exit
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
$jobs = $input->getArgument('job');
|
$jobs = $input->getArgument('job');
|
||||||
|
|
||||||
// handle force option
|
// handle force option
|
||||||
if ($input->getOption('force')) {
|
if ($input->getOption('force')) {
|
||||||
// rebuild all config files
|
if (empty($jobs) || in_array('tasks', $jobs)) {
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_DNS);
|
Cronjob::inserttask(TaskId::REBUILD_DNS);
|
||||||
Cronjob::inserttask(TaskId::CREATE_QUOTA);
|
Cronjob::inserttask(TaskId::CREATE_QUOTA);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_CRON);
|
Cronjob::inserttask(TaskId::REBUILD_CRON);
|
||||||
array_push($jobs, 'tasks');
|
array_push($jobs, 'tasks');
|
||||||
|
}
|
||||||
define('CRON_IS_FORCED', 1);
|
define('CRON_IS_FORCED', 1);
|
||||||
}
|
}
|
||||||
// handle debug option
|
// handle debug option
|
||||||
@@ -86,7 +92,7 @@ final class MasterCron extends CliCommand
|
|||||||
if ($input->getOption('run-task')) {
|
if ($input->getOption('run-task')) {
|
||||||
$tasks_to_run = $input->getOption('run-task');
|
$tasks_to_run = $input->getOption('run-task');
|
||||||
foreach ($tasks_to_run as $ttr) {
|
foreach ($tasks_to_run as $ttr) {
|
||||||
if (in_array($ttr, [1, 4, 10, 99])) {
|
if (in_array($ttr, [TaskId::REBUILD_VHOST, TaskId::REBUILD_DNS, TaskId::CREATE_QUOTA, TaskId::REBUILD_CRON])) {
|
||||||
Cronjob::inserttask($ttr);
|
Cronjob::inserttask($ttr);
|
||||||
array_push($jobs, 'tasks');
|
array_push($jobs, 'tasks');
|
||||||
} else {
|
} else {
|
||||||
@@ -111,8 +117,8 @@ final class MasterCron extends CliCommand
|
|||||||
]);
|
]);
|
||||||
$this->cronLog->setCronDebugFlag(defined('CRON_DEBUG_FLAG'));
|
$this->cronLog->setCronDebugFlag(defined('CRON_DEBUG_FLAG'));
|
||||||
|
|
||||||
// check whether there are actual tasks to perform by 'tasks'-cron so
|
// check whether there are actual tasks to perform by 'tasks'-cron, so
|
||||||
// we dont regenerate files unnecessarily
|
// we don't regenerate files unnecessarily
|
||||||
$tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`");
|
$tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`");
|
||||||
$tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC);
|
$tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
@@ -161,6 +167,9 @@ final class MasterCron extends CliCommand
|
|||||||
FroxlorLogger::getInstanceOf()->setCronLog(0);
|
FroxlorLogger::getInstanceOf()->setCronLog(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clean up possible old login-links
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_LOGINLINKS . "` WHERE `valid_until` < UNIX_TIMESTAMP()");
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ final class ValidateAcmeWebroot extends CliCommand
|
|||||||
'domain' => Settings::Get('system.hostname')
|
'domain' => Settings::Get('system.hostname')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$upd_stmt = Database::prepare("UPDATE domain_ssl_settings SET expirationdate=NULL WHERE `domainid` = :did");
|
$upd_stmt = Database::prepare("UPDATE domain_ssl_settings SET `validtodate`=NULL WHERE `domainid` = :did");
|
||||||
$acmesh_dir = dirname(Settings::Get('system.acmeshpath'));
|
$acmesh_dir = dirname(Settings::Get('system.acmeshpath'));
|
||||||
$acmesh_challenge_dir = rtrim(FileDir::makeCorrectDir(Settings::Get('system.letsencryptchallengepath')), "/");
|
$acmesh_challenge_dir = rtrim(FileDir::makeCorrectDir(Settings::Get('system.letsencryptchallengepath')), "/");
|
||||||
$recommended = rtrim(FileDir::makeCorrectDir(Froxlor::getInstallDir()), "/");
|
$recommended = rtrim(FileDir::makeCorrectDir(Froxlor::getInstallDir()), "/");
|
||||||
|
|||||||
95
lib/Froxlor/Cron/Backup/BackupCron.php
Normal file
95
lib/Froxlor/Cron/Backup/BackupCron.php
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Cron\Backup;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\Backup\Storages\StorageFactory;
|
||||||
|
use Froxlor\Cron\Forkable;
|
||||||
|
use Froxlor\Cron\FroxlorCron;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
class BackupCron extends FroxlorCron
|
||||||
|
{
|
||||||
|
use Forkable;
|
||||||
|
|
||||||
|
public static function run()
|
||||||
|
{
|
||||||
|
if (!Settings::Get('backup.enabled')) {
|
||||||
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'BackupCron: disabled - exiting');
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_BACKUP_STORAGES . "`");
|
||||||
|
Database::pexecute($stmt);
|
||||||
|
|
||||||
|
$storages = [];
|
||||||
|
while ($storage = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$storages[$storage['id']] = $storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = Database::prepare("SELECT
|
||||||
|
customerid,
|
||||||
|
loginname,
|
||||||
|
adminid,
|
||||||
|
backup,
|
||||||
|
guid,
|
||||||
|
documentroot
|
||||||
|
FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `backup` > 0
|
||||||
|
");
|
||||||
|
Database::pexecute($stmt);
|
||||||
|
|
||||||
|
$customers = [];
|
||||||
|
while ($customer = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$customer['storage'] = $storages[$customer['backup']];
|
||||||
|
$customers[] = $customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::runFork([self::class, 'handle'], $customers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private static function handle(array $userdata)
|
||||||
|
{
|
||||||
|
echo "BackupCron: started - creating customer backup for user " . $userdata['loginname'] . "\n";
|
||||||
|
|
||||||
|
$backupStorage = StorageFactory::fromType($userdata['storage']['type'], $userdata);
|
||||||
|
// initialize storage
|
||||||
|
$backupStorage->init();
|
||||||
|
// do what is required to obtain files/archives and move/upload
|
||||||
|
$backupStorage->prepareFiles();
|
||||||
|
// upload/move to target
|
||||||
|
$backupStorage->createFromFiles();
|
||||||
|
// remove by retention
|
||||||
|
$backupStorage->removeOld();
|
||||||
|
|
||||||
|
echo "BackupCron: finished - creating customer backup for user " . $userdata['loginname'] . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,8 +62,8 @@ class Bind extends DnsBase
|
|||||||
$this->bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n";
|
$this->bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n";
|
||||||
|
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
if ($domain['ismainbutsubto'] > 0) {
|
if ($domain['is_child']) {
|
||||||
// domains with ismainbutsubto>0 are handled by recursion within walkDomainList()
|
// domains that are subdomains to other main domains are handled by recursion within walkDomainList()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$this->walkDomainList($domain, $domains);
|
$this->walkDomainList($domain, $domains);
|
||||||
@@ -114,7 +114,7 @@ class Bind extends DnsBase
|
|||||||
$isFroxlorHostname = true;
|
$isFroxlorHostname = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($domain['ismainbutsubto'] == 0) {
|
if (!$domain['is_child']) {
|
||||||
$zoneContent = (string)Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
|
$zoneContent = (string)Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
|
||||||
$domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone';
|
$domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone';
|
||||||
$zonefile_name = FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']);
|
$zonefile_name = FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
namespace Froxlor\Cron\Dns;
|
namespace Froxlor\Cron\Dns;
|
||||||
|
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\Domain\Domain;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\PhpHelper;
|
use Froxlor\PhpHelper;
|
||||||
@@ -210,7 +211,6 @@ abstract class DnsBase
|
|||||||
`d`.`dkim`,
|
`d`.`dkim`,
|
||||||
`d`.`dkim_id`,
|
`d`.`dkim_id`,
|
||||||
`d`.`dkim_pubkey`,
|
`d`.`dkim_pubkey`,
|
||||||
`d`.`ismainbutsubto`,
|
|
||||||
`c`.`loginname`,
|
`c`.`loginname`,
|
||||||
`c`.`guid`
|
`c`.`guid`
|
||||||
FROM
|
FROM
|
||||||
@@ -219,7 +219,7 @@ abstract class DnsBase
|
|||||||
WHERE
|
WHERE
|
||||||
`d`.`isbinddomain` = '1'
|
`d`.`isbinddomain` = '1'
|
||||||
ORDER BY
|
ORDER BY
|
||||||
`d`.`domain` ASC
|
LENGTH(`d`.`domain`), `d`.`domain` ASC
|
||||||
");
|
");
|
||||||
|
|
||||||
$domains = [];
|
$domains = [];
|
||||||
@@ -241,7 +241,6 @@ abstract class DnsBase
|
|||||||
'bindserial' => date('Ymd') . '00',
|
'bindserial' => date('Ymd') . '00',
|
||||||
'dkim' => '0',
|
'dkim' => '0',
|
||||||
'iswildcarddomain' => '1',
|
'iswildcarddomain' => '1',
|
||||||
'ismainbutsubto' => '0',
|
|
||||||
'zonefile' => '',
|
'zonefile' => '',
|
||||||
'froxlorhost' => '1'
|
'froxlorhost' => '1'
|
||||||
];
|
];
|
||||||
@@ -257,18 +256,23 @@ abstract class DnsBase
|
|||||||
if (!isset($domains[$key]['children'])) {
|
if (!isset($domains[$key]['children'])) {
|
||||||
$domains[$key]['children'] = [];
|
$domains[$key]['children'] = [];
|
||||||
}
|
}
|
||||||
if ($domains[$key]['ismainbutsubto'] > 0) {
|
if (!isset($domains[$key]['is_child'])) {
|
||||||
if (isset($domains[$domains[$key]['ismainbutsubto']])) {
|
$domains[$key]['is_child'] = false;
|
||||||
$domains[$domains[$key]['ismainbutsubto']]['children'][] = $domains[$key]['id'];
|
}
|
||||||
} else {
|
$children = Domain::getMainSubdomainIds($key);
|
||||||
$domains[$key]['ismainbutsubto'] = 0;
|
if (count($children) > 0) {
|
||||||
|
foreach ($children as $child) {
|
||||||
|
if (isset($domains[$child])) {
|
||||||
|
$domains[$key]['children'][] = $domains[$child]['id'];
|
||||||
|
$domains[$child]['is_child'] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, str_pad('domId', 9, ' ') . str_pad('domain', 40, ' ') . 'ismainbutsubto ' . str_pad('parent domain', 40, ' ') . "list of child domain ids");
|
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, str_pad('domId', 9, ' ') . str_pad('domain', 40, ' ') . "list of child domain ids");
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
$logLine = str_pad($domain['id'], 9, ' ') . str_pad($domain['domain'], 40, ' ') . str_pad($domain['ismainbutsubto'], 15, ' ') . str_pad(((isset($domains[$domain['ismainbutsubto']])) ? $domains[$domain['ismainbutsubto']]['domain'] : '-'), 40, ' ') . join(', ', $domain['children']);
|
$logLine = str_pad($domain['id'], 9, ' ') . str_pad($domain['domain'], 40, ' ') . join(', ', $domain['children']);
|
||||||
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, $logLine);
|
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, $logLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ class PowerDNS extends DnsBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
if ($domain['ismainbutsubto'] > 0) {
|
if ($domain['is_child']) {
|
||||||
// domains with ismainbutsubto>0 are handled by recursion within walkDomainList()
|
// domains that are subdomains to other main domains are handled by recursion within walkDomainList()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$this->walkDomainList($domain, $domains);
|
$this->walkDomainList($domain, $domains);
|
||||||
@@ -108,7 +108,7 @@ class PowerDNS extends DnsBase
|
|||||||
$isFroxlorHostname = true;
|
$isFroxlorHostname = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($domain['ismainbutsubto'] == 0) {
|
if (!$domain['is_child']) {
|
||||||
$zoneContent = Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
|
$zoneContent = Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
|
||||||
if (count($subzones)) {
|
if (count($subzones)) {
|
||||||
foreach ($subzones as $subzone) {
|
foreach ($subzones as $subzone) {
|
||||||
|
|||||||
57
lib/Froxlor/Cron/Forkable.php
Normal file
57
lib/Froxlor/Cron/Forkable.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Cron;
|
||||||
|
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
|
||||||
|
trait Forkable
|
||||||
|
{
|
||||||
|
public static function runFork($closure, array $attributes = [], int $concurrentChildren = 3)
|
||||||
|
{
|
||||||
|
$childrenPids = [];
|
||||||
|
|
||||||
|
// We only fork if pcntl_fork is available and nofork flag is not set
|
||||||
|
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
|
||||||
|
foreach ($attributes as $closureAttributes) {
|
||||||
|
// We close the database - connection before we fork, so we don't share resources with the child
|
||||||
|
Database::needRoot(false); // this forces the connection to be set to null
|
||||||
|
$pid = pcntl_fork();
|
||||||
|
|
||||||
|
if ($pid == -1) {
|
||||||
|
exit("Error forking...\n");
|
||||||
|
} elseif ($pid == 0) {
|
||||||
|
// re-create db
|
||||||
|
Database::needRoot(false);
|
||||||
|
$closure($closureAttributes);
|
||||||
|
exit();
|
||||||
|
} else {
|
||||||
|
$childrenPids[] = $pid;
|
||||||
|
while (count($childrenPids) >= $concurrentChildren) {
|
||||||
|
foreach ($childrenPids as $key => $pid) {
|
||||||
|
$res = pcntl_waitpid($pid, $status, WNOHANG);
|
||||||
|
// If the process has already exited
|
||||||
|
if ($res == -1 || $res > 0) {
|
||||||
|
unset($childrenPids[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (pcntl_waitpid(0, $status) != -1);
|
||||||
|
} else {
|
||||||
|
if (!defined('CRON_NOFORK_FLAG')) {
|
||||||
|
if (extension_loaded('pcntl')) {
|
||||||
|
$msg = "PHP compiled with pcntl but pcntl_fork function is not available.";
|
||||||
|
} else {
|
||||||
|
$msg = "PHP compiled without pcntl.";
|
||||||
|
}
|
||||||
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, $msg . " Not forking " . self::class . ", this may take a long time!");
|
||||||
|
}
|
||||||
|
foreach ($attributes as $closureAttributes) {
|
||||||
|
$closure($closureAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -630,29 +630,6 @@ class Apache extends HttpConfigBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the filename for the virtualhost
|
|
||||||
*/
|
|
||||||
protected function getVhostFilename($domain, $ssl_vhost = false)
|
|
||||||
{
|
|
||||||
if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) {
|
|
||||||
$vhost_no = '35';
|
|
||||||
} elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) {
|
|
||||||
$vhost_no = '30';
|
|
||||||
} else {
|
|
||||||
// number of dots in a domain specifies it's position (and depth of subdomain) starting at 29 going downwards on higher depth
|
|
||||||
$vhost_no = (string)(30 - substr_count($domain['domain'], ".") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ssl_vhost === true) {
|
|
||||||
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_ssl_vhost_' . $domain['domain'] . '.conf');
|
|
||||||
} else {
|
|
||||||
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_normal_vhost_' . $domain['domain'] . '.conf');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $vhost_filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We compose the virtualhost entry for one domain
|
* We compose the virtualhost entry for one domain
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -126,6 +126,9 @@ class ApacheFcgi extends Apache
|
|||||||
|
|
||||||
// mod_proxy stuff for apache-2.4
|
// mod_proxy stuff for apache-2.4
|
||||||
if (Settings::Get('system.apache24') == '1' && Settings::Get('phpfpm.use_mod_proxy') == '1') {
|
if (Settings::Get('system.apache24') == '1' && Settings::Get('phpfpm.use_mod_proxy') == '1') {
|
||||||
|
|
||||||
|
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||||
|
|
||||||
$filesmatch = $phpconfig['fpm_settings']['limit_extensions'];
|
$filesmatch = $phpconfig['fpm_settings']['limit_extensions'];
|
||||||
$extensions = explode(" ", $filesmatch);
|
$extensions = explode(" ", $filesmatch);
|
||||||
$filesmatch = "";
|
$filesmatch = "";
|
||||||
@@ -141,23 +144,19 @@ class ApacheFcgi extends Apache
|
|||||||
$php_options_text .= ' </FilesMatch>' . "\n";
|
$php_options_text .= ' </FilesMatch>' . "\n";
|
||||||
|
|
||||||
$mypath_dir = new Directory($domain['documentroot']);
|
$mypath_dir = new Directory($domain['documentroot']);
|
||||||
|
// only create the "require all granted" directive if there is no active directory-protection
|
||||||
// only create the require all granted if there is not active directory-protection
|
|
||||||
// for this path, as this would be the first require and therefore grant all access
|
// for this path, as this would be the first require and therefore grant all access
|
||||||
if ($mypath_dir->isUserProtected() == false) {
|
if ($mypath_dir->isUserProtected() == false) {
|
||||||
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
|
||||||
if ($phpconfig['pass_authorizationheader'] == '1') {
|
if ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
$php_options_text .= ' CGIPassAuth On' . "\n";
|
$php_options_text .= ' CGIPassAuth On' . "\n";
|
||||||
}
|
}
|
||||||
$php_options_text .= ' Require all granted' . "\n";
|
$php_options_text .= ' Require all granted' . "\n";
|
||||||
$php_options_text .= ' AllowOverride All' . "\n";
|
$php_options_text .= ' AllowOverride All' . "\n";
|
||||||
$php_options_text .= ' </Directory>' . "\n";
|
|
||||||
} elseif ($phpconfig['pass_authorizationheader'] == '1') {
|
} elseif ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
// allow Pass of Authorization header
|
// allow Pass of Authorization header
|
||||||
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
|
||||||
$php_options_text .= ' CGIPassAuth On' . "\n";
|
$php_options_text .= ' CGIPassAuth On' . "\n";
|
||||||
$php_options_text .= ' </Directory>' . "\n";
|
|
||||||
}
|
}
|
||||||
|
$php_options_text .= ' </Directory>' . "\n";
|
||||||
} else {
|
} else {
|
||||||
$addheader = "";
|
$addheader = "";
|
||||||
if ($phpconfig['pass_authorizationheader'] == '1') {
|
if ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
@@ -196,6 +195,9 @@ class ApacheFcgi extends Apache
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$php_options_text .= ' FcgidIdleTimeout ' . Settings::Get('system.mod_fcgid_idle_timeout') . "\n";
|
$php_options_text .= ' FcgidIdleTimeout ' . Settings::Get('system.mod_fcgid_idle_timeout') . "\n";
|
||||||
|
if ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
|
$php_options_text .= ' FcgidPassHeader Authorization' . "\n";
|
||||||
|
}
|
||||||
if ((int)Settings::Get('system.mod_fcgid_wrapper') == 0) {
|
if ((int)Settings::Get('system.mod_fcgid_wrapper') == 0) {
|
||||||
$php_options_text .= ' SuexecUserGroup "' . $domain['loginname'] . '" "' . $domain['loginname'] . '"' . "\n";
|
$php_options_text .= ' SuexecUserGroup "' . $domain['loginname'] . '" "' . $domain['loginname'] . '"' . "\n";
|
||||||
$php_options_text .= ' ScriptAlias /php/ ' . $php->getInterface()->getConfigDir() . "\n";
|
$php_options_text .= ' ScriptAlias /php/ ' . $php->getInterface()->getConfigDir() . "\n";
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace Froxlor\Cron\Http;
|
|||||||
use Froxlor\Cron\Http\LetsEncrypt\AcmeSh;
|
use Froxlor\Cron\Http\LetsEncrypt\AcmeSh;
|
||||||
use Froxlor\Cron\Http\Php\Fpm;
|
use Froxlor\Cron\Http\Php\Fpm;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\Domain\Domain;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
@@ -179,7 +180,7 @@ class HttpConfigBase
|
|||||||
$froxlor_ssl_settings_stmt = Database::prepare("
|
$froxlor_ssl_settings_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
||||||
WHERE `domainid` = '0' AND
|
WHERE `domainid` = '0' AND
|
||||||
(`expirationdate` < DATE_ADD(NOW(), INTERVAL 30 DAY) OR `expirationdate` IS NULL)
|
(`validtodate` < DATE_ADD(NOW(), INTERVAL 30 DAY) OR `validtodate` IS NULL)
|
||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
if ($froxlor_ssl && !empty($froxlor_ssl['ssl_cert_file'])) {
|
if ($froxlor_ssl && !empty($froxlor_ssl['ssl_cert_file'])) {
|
||||||
@@ -187,4 +188,18 @@ class HttpConfigBase
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the filename for the virtualhost
|
||||||
|
*/
|
||||||
|
protected function getVhostFilename(array $domain, bool $ssl_vhost = false, bool $filename_only = false)
|
||||||
|
{
|
||||||
|
// number of dots in a domain specifies its position (and depth of subdomain) starting at 35 going downwards on higher depth
|
||||||
|
$vhost_no = (string)(35 - substr_count($domain['domain'], ".") + 1);
|
||||||
|
$filename = $vhost_no . '_froxlor_' . ($ssl_vhost ? 'ssl' : 'normal') . '_vhost_' . $domain['domain'] . '.conf';
|
||||||
|
if ($filename_only) {
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
return FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
`ssl_cert_chainfile` = :chain,
|
`ssl_cert_chainfile` = :chain,
|
||||||
`ssl_csr_file` = :csr,
|
`ssl_csr_file` = :csr,
|
||||||
`ssl_fullchain_file` = :fullchain,
|
`ssl_fullchain_file` = :fullchain,
|
||||||
`expirationdate` = :expirationdate
|
`validfromdate` = :validfromdate,
|
||||||
|
`validtodate` = :validtodate,
|
||||||
|
`issuer` = :issuer
|
||||||
");
|
");
|
||||||
|
|
||||||
// prepare domain update sql
|
// prepare domain update sql
|
||||||
@@ -136,7 +138,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
'lepublickey' => Settings::Get('system.lepublickey'),
|
'lepublickey' => Settings::Get('system.lepublickey'),
|
||||||
'leregistered' => Settings::Get('system.leregistered'),
|
'leregistered' => Settings::Get('system.leregistered'),
|
||||||
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
||||||
'expirationdate' => null,
|
'validfromdate' => null,
|
||||||
|
'validtodate' => null,
|
||||||
|
'issuer' => "",
|
||||||
'ssl_cert_file' => null,
|
'ssl_cert_file' => null,
|
||||||
'ssl_key_file' => null,
|
'ssl_key_file' => null,
|
||||||
'ssl_ca_file' => null,
|
'ssl_ca_file' => null,
|
||||||
@@ -171,7 +175,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
'lepublickey' => Settings::Get('system.lepublickey'),
|
'lepublickey' => Settings::Get('system.lepublickey'),
|
||||||
'leregistered' => Settings::Get('system.leregistered'),
|
'leregistered' => Settings::Get('system.leregistered'),
|
||||||
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
||||||
'expirationdate' => is_array($renew_froxlor) ? $renew_froxlor['expirationdate'] : date('Y-m-d H:i:s', 0),
|
'validfromdate' => is_array($renew_froxlor) ? $renew_froxlor['validfromdate'] : date('Y-m-d H:i:s', 0),
|
||||||
|
'validtodate' => is_array($renew_froxlor) ? $renew_froxlor['validtodate'] : date('Y-m-d H:i:s', 0),
|
||||||
|
'issuer' => is_array($renew_froxlor) ? $renew_froxlor['issuer'] : "",
|
||||||
'ssl_cert_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_cert_file'] : null,
|
'ssl_cert_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_cert_file'] : null,
|
||||||
'ssl_key_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_key_file'] : null,
|
'ssl_key_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_key_file'] : null,
|
||||||
'ssl_ca_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_ca_file'] : null,
|
'ssl_ca_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_ca_file'] : null,
|
||||||
@@ -187,7 +193,7 @@ class AcmeSh extends FroxlorCron
|
|||||||
'loginname' => $domain['loginname'],
|
'loginname' => $domain['loginname'],
|
||||||
'adminsession' => 0
|
'adminsession' => 0
|
||||||
]);
|
]);
|
||||||
if (defined('CRON_IS_FORCED') || self::checkFsFilesAreNewer($domain['domain'], $domain['expirationdate'])) {
|
if (defined('CRON_IS_FORCED') || self::checkFsFilesAreNewer($domain['domain'], $domain['validtodate'])) {
|
||||||
self::certToDb($domain, $cronlog, []);
|
self::certToDb($domain, $cronlog, []);
|
||||||
$changedetected = 1;
|
$changedetected = 1;
|
||||||
}
|
}
|
||||||
@@ -221,16 +227,21 @@ class AcmeSh extends FroxlorCron
|
|||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
// also check for possible existing certificate
|
// also check for possible existing certificate
|
||||||
if (!$froxlor_ssl && !self::checkFsFilesAreNewer(Settings::Get('system.hostname'), date('Y-m-d H:i:s'))) {
|
if (($froxlor_ssl && empty($froxlor_ssl['validtodate']))
|
||||||
|
|| (!$froxlor_ssl && !self::checkFsFilesAreNewer(Settings::Get('system.hostname'), date('Y-m-d H:i:s')))
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function checkFsFilesAreNewer($domain, $cert_date = 0)
|
private static function checkFsFilesAreNewer($domain, $cert_date = 0): bool
|
||||||
{
|
{
|
||||||
$certificate_folder = self::getWorkingDirFromEnv(strtolower($domain));
|
$certificate_folder = self::getCertificateFolder(strtolower($domain));
|
||||||
|
if (empty($certificate_folder)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$ssl_file = FileDir::makeCorrectFile($certificate_folder . '/' . strtolower($domain) . '.cer');
|
$ssl_file = FileDir::makeCorrectFile($certificate_folder . '/' . strtolower($domain) . '.cer');
|
||||||
|
|
||||||
if (is_dir($certificate_folder) && file_exists($ssl_file) && is_readable($ssl_file)) {
|
if (is_dir($certificate_folder) && file_exists($ssl_file) && is_readable($ssl_file)) {
|
||||||
@@ -242,9 +253,13 @@ class AcmeSh extends FroxlorCron
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getWorkingDirFromEnv($domain = "", $forced_noecc = false)
|
public static function getWorkingDirFromEnv($domain = "", $forced_ecc = false): string
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.leecc') > 0 && !$forced_noecc) {
|
// first try without _ecc either if it's enabled currently or not as
|
||||||
|
// it might have been at some point so there is a chance we have certificates
|
||||||
|
// with and without _ecc - the method getCertificateFolder() will check both
|
||||||
|
// possibilities
|
||||||
|
if ($forced_ecc) {
|
||||||
$domain .= "_ecc";
|
$domain .= "_ecc";
|
||||||
}
|
}
|
||||||
$env_file = FileDir::makeCorrectFile(dirname(self::getAcmeSh()) . '/acme.sh.env');
|
$env_file = FileDir::makeCorrectFile(dirname(self::getAcmeSh()) . '/acme.sh.env');
|
||||||
@@ -254,7 +269,7 @@ class AcmeSh extends FroxlorCron
|
|||||||
cut -d'"' -f2
|
cut -d'"' -f2
|
||||||
EOC;
|
EOC;
|
||||||
exec('grep "LE_WORKING_DIR" ' . escapeshellarg($env_file) . ' | ' . $cut, $output);
|
exec('grep "LE_WORKING_DIR" ' . escapeshellarg($env_file) . ' | ' . $cut, $output);
|
||||||
if (is_array($output) && !empty($output) && isset($output[0]) && !empty($output[0])) {
|
if (is_array($output) && !empty($output) && !empty($output[0])) {
|
||||||
return FileDir::makeCorrectDir($output[0] . "/" . $domain);
|
return FileDir::makeCorrectDir($output[0] . "/" . $domain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,7 +294,9 @@ EOC;
|
|||||||
SELECT
|
SELECT
|
||||||
domssl.`id`,
|
domssl.`id`,
|
||||||
domssl.`domainid`,
|
domssl.`domainid`,
|
||||||
domssl.`expirationdate`,
|
domssl.`validfromdate`,
|
||||||
|
domssl.`validtodate`,
|
||||||
|
domssl.`issuer`,
|
||||||
domssl.`ssl_cert_file`,
|
domssl.`ssl_cert_file`,
|
||||||
domssl.`ssl_key_file`,
|
domssl.`ssl_key_file`,
|
||||||
domssl.`ssl_ca_file`,
|
domssl.`ssl_ca_file`,
|
||||||
@@ -306,7 +323,7 @@ EOC;
|
|||||||
AND dom.`letsencrypt` = 1
|
AND dom.`letsencrypt` = 1
|
||||||
AND dom.`aliasdomain` IS NULL
|
AND dom.`aliasdomain` IS NULL
|
||||||
AND dom.`iswildcarddomain` = 0
|
AND dom.`iswildcarddomain` = 0
|
||||||
AND domssl.`expirationdate` IS NULL
|
AND domssl.`validtodate` IS NULL
|
||||||
");
|
");
|
||||||
$customer_ssl = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
|
$customer_ssl = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
if ($customer_ssl) {
|
if ($customer_ssl) {
|
||||||
@@ -330,7 +347,7 @@ EOC;
|
|||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
// also check for possible existing certificate
|
// also check for possible existing certificate
|
||||||
if ($froxlor_ssl && self::checkFsFilesAreNewer(Settings::Get('system.hostname'), $froxlor_ssl['expirationdate'])) {
|
if ($froxlor_ssl && self::checkFsFilesAreNewer(Settings::Get('system.hostname'), $froxlor_ssl['validtodate'])) {
|
||||||
return $froxlor_ssl;
|
return $froxlor_ssl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -346,7 +363,9 @@ EOC;
|
|||||||
SELECT
|
SELECT
|
||||||
domssl.`id`,
|
domssl.`id`,
|
||||||
domssl.`domainid`,
|
domssl.`domainid`,
|
||||||
domssl.`expirationdate`,
|
domssl.`validfromdate`,
|
||||||
|
domssl.`validtodate`,
|
||||||
|
domssl.`issuer`,
|
||||||
domssl.`ssl_cert_file`,
|
domssl.`ssl_cert_file`,
|
||||||
domssl.`ssl_key_file`,
|
domssl.`ssl_key_file`,
|
||||||
dom.`domain`,
|
dom.`domain`,
|
||||||
@@ -370,7 +389,7 @@ EOC;
|
|||||||
if ($renew_certs) {
|
if ($renew_certs) {
|
||||||
if ($check) {
|
if ($check) {
|
||||||
foreach ($renew_certs as $cert) {
|
foreach ($renew_certs as $cert) {
|
||||||
if (self::checkFsFilesAreNewer($cert['domain'], $cert['expirationdate'])) {
|
if (self::checkFsFilesAreNewer($cert['domain'], $cert['validtodate'])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -453,7 +472,7 @@ EOC;
|
|||||||
// Only issue let's encrypt certificate if no broken ssl_redirect is enabled
|
// Only issue let's encrypt certificate if no broken ssl_redirect is enabled
|
||||||
if ($certrow['ssl_redirect'] != 2) {
|
if ($certrow['ssl_redirect'] != 2) {
|
||||||
$do_force = false;
|
$do_force = false;
|
||||||
if (!empty($certrow['ssl_cert_file']) && empty($certrow['expirationdate'])) {
|
if (!empty($certrow['ssl_cert_file']) && empty($certrow['validtodate'])) {
|
||||||
// domain changed (SAN or similar)
|
// domain changed (SAN or similar)
|
||||||
$do_force = true;
|
$do_force = true;
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']);
|
||||||
@@ -537,6 +556,10 @@ EOC;
|
|||||||
Settings::Set('system.le_froxlor_enabled', 0);
|
Settings::Set('system.le_froxlor_enabled', 0);
|
||||||
}
|
}
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Let's Encrypt deactivated for domain " . $domain);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Let's Encrypt deactivated for domain " . $domain);
|
||||||
|
if (!defined('CRON_IS_FORCED') && !defined('CRON_DEBUG_FLAG')) {
|
||||||
|
// email info to admin that lets encrypt has been disabled for this domain
|
||||||
|
Cronjob::notifyMailToAdmin("Let's Encrypt has been deactivated for domain '" . $domain . "' due to failed dns validation (wrong or no IP address)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -567,11 +590,20 @@ EOC;
|
|||||||
$acmesh_cmd .= " --debug";
|
$acmesh_cmd .= " --debug";
|
||||||
}
|
}
|
||||||
|
|
||||||
$acme_result = FileDir::safe_exec($acmesh_cmd);
|
$exit_code = null;
|
||||||
|
$acme_result = FileDir::safe_exec($acmesh_cmd, $exit_code);
|
||||||
// debug output of acme.sh run
|
// debug output of acme.sh run
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, implode("\n", $acme_result));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, implode("\n", $acme_result));
|
||||||
|
|
||||||
self::certToDb($certrow, $cronlog, $acme_result);
|
if ($exit_code != 0) {
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, "Non-successful exit-code returned :(");
|
||||||
|
if (!defined('CRON_IS_FORCED') && !defined('CRON_DEBUG_FLAG')) {
|
||||||
|
Cronjob::notifyMailToAdmin("Let's Encrypt certificate could not be obtained for: " . implode(", ", $domains) . "\n\n" . implode("\n", $acme_result));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, "Successful exit-code returned - storing certificate");
|
||||||
|
self::certToDb($certrow, $cronlog, $acme_result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,7 +626,9 @@ EOC;
|
|||||||
'chain' => $return['chain'],
|
'chain' => $return['chain'],
|
||||||
'csr' => $return['csr'],
|
'csr' => $return['csr'],
|
||||||
'fullchain' => $return['fullchain'],
|
'fullchain' => $return['fullchain'],
|
||||||
'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t'])
|
'validfromdate' => date('Y-m-d H:i:s', $newcert['validFrom_time_t']),
|
||||||
|
'validtodate' => date('Y-m-d H:i:s', $newcert['validTo_time_t']),
|
||||||
|
'issuer' => $newcert['issuer']['O'] ?? ""
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($certrow['ssl_redirect'] == 3) {
|
if ($certrow['ssl_redirect'] == 3) {
|
||||||
@@ -621,35 +655,21 @@ EOC;
|
|||||||
*/
|
*/
|
||||||
private static function readCertificateToVar($domain, &$return, &$cronlog)
|
private static function readCertificateToVar($domain, &$return, &$cronlog)
|
||||||
{
|
{
|
||||||
$certificate_folder = self::getWorkingDirFromEnv($domain);
|
$certificate_folder = self::getCertificateFolder($domain);
|
||||||
$certificate_folder_noecc = null;
|
|
||||||
if (Settings::Get('system.leecc') > 0) {
|
|
||||||
$certificate_folder_noecc = self::getWorkingDirFromEnv($domain, true);
|
|
||||||
}
|
|
||||||
$certificate_folder = FileDir::makeCorrectDir($certificate_folder);
|
|
||||||
|
|
||||||
if (is_dir($certificate_folder) || is_dir($certificate_folder_noecc)) {
|
if (!empty($certificate_folder)) {
|
||||||
foreach (
|
$certificate_files = [
|
||||||
[
|
'crt' => $domain . '.cer',
|
||||||
'crt' => $domain . '.cer',
|
'key' => $domain . '.key',
|
||||||
'key' => $domain . '.key',
|
'chain' => 'ca.cer',
|
||||||
'chain' => 'ca.cer',
|
'fullchain' => 'fullchain.cer',
|
||||||
'fullchain' => 'fullchain.cer',
|
'csr' => $domain . '.csr'
|
||||||
'csr' => $domain . '.csr'
|
];
|
||||||
] as $index => $sslfile
|
foreach ($certificate_files as $index => $sslfile) {
|
||||||
) {
|
|
||||||
$ssl_file = FileDir::makeCorrectFile($certificate_folder . '/' . $sslfile);
|
$ssl_file = FileDir::makeCorrectFile($certificate_folder . '/' . $sslfile);
|
||||||
if (file_exists($ssl_file)) {
|
if (file_exists($ssl_file)) {
|
||||||
$return[$index] = file_get_contents($ssl_file);
|
$return[$index] = file_get_contents($ssl_file);
|
||||||
} else {
|
} else {
|
||||||
if (!empty($certificate_folder_noecc)) {
|
|
||||||
$ssl_file_fb = 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 . "'");
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find file '" . $sslfile . "' in '" . $certificate_folder . "'");
|
||||||
$return[$index] = null;
|
$return[$index] = null;
|
||||||
}
|
}
|
||||||
@@ -658,4 +678,18 @@ EOC;
|
|||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find certificate-folder '" . $certificate_folder . "'");
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find certificate-folder '" . $certificate_folder . "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function getCertificateFolder(string $domain): string
|
||||||
|
{
|
||||||
|
$certificate_folder = self::getWorkingDirFromEnv(strtolower($domain));
|
||||||
|
if (file_exists($certificate_folder)) {
|
||||||
|
return $certificate_folder;
|
||||||
|
}
|
||||||
|
$certificate_folder_ecc = self::getWorkingDirFromEnv($domain, true);
|
||||||
|
if (file_exists($certificate_folder_ecc)) {
|
||||||
|
return $certificate_folder_ecc;
|
||||||
|
}
|
||||||
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find certificate-folder for domain '" . $domain . "'");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -336,24 +336,9 @@ class Lighttpd extends HttpConfigBase
|
|||||||
$_pos = strrpos($_tmp_path, '/');
|
$_pos = strrpos($_tmp_path, '/');
|
||||||
$_inc_path = substr($_tmp_path, $_pos + 1);
|
$_inc_path = substr($_tmp_path, $_pos + 1);
|
||||||
|
|
||||||
// maindomain
|
$filename = self::getVhostFilename($domain, ($ssl == '1'), true);
|
||||||
if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) {
|
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/vhosts/' . $filename);
|
||||||
$vhost_no = '50';
|
$included_vhosts[] = $_inc_path . '/vhosts/' . $filename;
|
||||||
} elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) {
|
|
||||||
// sub-but-main-domain
|
|
||||||
$vhost_no = '51';
|
|
||||||
} else {
|
|
||||||
// subdomains
|
|
||||||
// number of dots in a domain specifies it's position (and depth of subdomain) starting at 89 going downwards on higher depth
|
|
||||||
$vhost_no = (string)(90 - substr_count($domain['domain'], ".") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ssl == '1') {
|
|
||||||
$vhost_no = (int)$vhost_no += 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/vhosts/' . $vhost_no . '_' . $domain['domain'] . '.conf');
|
|
||||||
$included_vhosts[] = $_inc_path . '/vhosts/' . $vhost_no . '_' . $domain['domain'] . '.conf';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($this->lighttpd_data[$vhost_filename])) {
|
if (!isset($this->lighttpd_data[$vhost_filename])) {
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ class Nginx extends HttpConfigBase
|
|||||||
$this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n";
|
$this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n";
|
||||||
|
|
||||||
// protect bin/
|
// protect bin/
|
||||||
$this->nginx_data[$vhost_filename] .= "\t" . 'location ~ ' . rtrim($relpath, "/") . '/(bin|cache|logs|tests|vendor) {' . "\n";
|
$this->nginx_data[$vhost_filename] .= "\t" . 'location ~ ^' . rtrim($relpath, "/") . '/(bin|cache|logs|tests|vendor) {' . "\n";
|
||||||
$this->nginx_data[$vhost_filename] .= "\t" . ' deny all;' . "\n";
|
$this->nginx_data[$vhost_filename] .= "\t" . ' deny all;' . "\n";
|
||||||
$this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n";
|
$this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n";
|
||||||
}
|
}
|
||||||
@@ -467,26 +467,6 @@ class Nginx extends HttpConfigBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getVhostFilename($domain, $ssl_vhost = false)
|
|
||||||
{
|
|
||||||
if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) {
|
|
||||||
$vhost_no = '35';
|
|
||||||
} elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) {
|
|
||||||
$vhost_no = '30';
|
|
||||||
} else {
|
|
||||||
// number of dots in a domain specifies it's position (and depth of subdomain) starting at 29 going downwards on higher depth
|
|
||||||
$vhost_no = (string)(30 - substr_count($domain['domain'], ".") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ssl_vhost === true) {
|
|
||||||
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_ssl_vhost_' . $domain['domain'] . '.conf');
|
|
||||||
} else {
|
|
||||||
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_normal_vhost_' . $domain['domain'] . '.conf');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $vhost_filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getVhostContent($domain, $ssl_vhost = false)
|
protected function getVhostContent($domain, $ssl_vhost = false)
|
||||||
{
|
{
|
||||||
if ($ssl_vhost === true && $domain['ssl'] != '1' && $domain['ssl_redirect'] != '1') {
|
if ($ssl_vhost === true && $domain['ssl'] != '1' && $domain['ssl_redirect'] != '1') {
|
||||||
@@ -1040,6 +1020,11 @@ class Nginx extends HttpConfigBase
|
|||||||
$path_options .= "\t\t" . 'auth_basic_user_file ' . FileDir::makeCorrectFile($single['usrf']) . ';' . "\n";
|
$path_options .= "\t\t" . 'auth_basic_user_file ' . FileDir::makeCorrectFile($single['usrf']) . ';' . "\n";
|
||||||
if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') {
|
if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') {
|
||||||
$path_options .= "\t\t" . 'index index.php index.html index.htm;' . "\n";
|
$path_options .= "\t\t" . 'index index.php index.html index.htm;' . "\n";
|
||||||
|
if ($domain['notryfiles'] != 1) {
|
||||||
|
$path_options .= "\t\t" . 'location ~ ^(.+?\.php)(/.*)?$ {' . "\n";
|
||||||
|
$path_options .= "\t\t\t" . 'try_files ' . $domain['nonexistinguri'] . ' @php;' . "\n";
|
||||||
|
$path_options .= "\t\t" . '}' . "\n\n";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$path_options .= "\t\t" . 'index index.html index.htm;' . "\n";
|
$path_options .= "\t\t" . 'index index.html index.htm;' . "\n";
|
||||||
}
|
}
|
||||||
@@ -1166,7 +1151,6 @@ class Nginx extends HttpConfigBase
|
|||||||
$phpopts .= "\t\tinclude " . Settings::Get('nginx.fastcgiparams') . ";\n";
|
$phpopts .= "\t\tinclude " . Settings::Get('nginx.fastcgiparams') . ";\n";
|
||||||
$phpopts .= "\t\tfastcgi_param SCRIPT_FILENAME \$request_filename;\n";
|
$phpopts .= "\t\tfastcgi_param SCRIPT_FILENAME \$request_filename;\n";
|
||||||
$phpopts .= "\t\tfastcgi_param PATH_INFO \$fastcgi_path_info;\n";
|
$phpopts .= "\t\tfastcgi_param PATH_INFO \$fastcgi_path_info;\n";
|
||||||
$phpopts .= "\t\ttry_files \$fastcgi_script_name =404;\n";
|
|
||||||
$phpopts .= "\t\tfastcgi_pass " . Settings::Get('system.nginx_php_backend') . ";\n";
|
$phpopts .= "\t\tfastcgi_pass " . Settings::Get('system.nginx_php_backend') . ";\n";
|
||||||
$phpopts .= "\t\tfastcgi_index index.php;\n";
|
$phpopts .= "\t\tfastcgi_index index.php;\n";
|
||||||
if ($domain['ssl'] == '1' && $ssl_vhost) {
|
if ($domain['ssl'] == '1' && $ssl_vhost) {
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ pm.max_children = 1
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now check if 'sendmail_path' has not beed set in the custom-php.ini
|
// now check if 'sendmail_path' has not been set in the custom-php.ini
|
||||||
// if not we use our fallback-default as usual
|
// if not we use our fallback-default as usual
|
||||||
if (strpos($fpm_config, 'php_admin_value[sendmail_path]') === false) {
|
if (strpos($fpm_config, 'php_admin_value[sendmail_path]') === false) {
|
||||||
$fpm_config .= 'php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f ' . $this->domain['email'] . "\n";
|
$fpm_config .= 'php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f ' . $this->domain['email'] . "\n";
|
||||||
@@ -342,8 +342,17 @@ pm.max_children = 1
|
|||||||
public function getSocketFile($createifnotexists = true)
|
public function getSocketFile($createifnotexists = true)
|
||||||
{
|
{
|
||||||
$socketdir = FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir'));
|
$socketdir = FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir'));
|
||||||
// add fpm-config-id to filename so it's unique for the fpm-daemon and doesn't interfere with running configs when reuilding
|
// add fpm-config-id to filename, so it's unique for the fpm-daemon and doesn't interfere with running configs when reuilding
|
||||||
$socket = strtolower(FileDir::makeCorrectFile($socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['loginname'] . '-' . $this->domain['domain'] . '-php-fpm.socket'));
|
$socket_filename = $socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['loginname'] . '-' . $this->domain['domain'] . '-php-fpm.socket';
|
||||||
|
if (strlen($socket_filename) > 100) {
|
||||||
|
// respect the unix socket-length limitation
|
||||||
|
$socket_filename = $socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['loginname'] . '-' . $this->domain['id'] . '-php-fpm.socket';
|
||||||
|
if (strlen($socket_filename) > 100) {
|
||||||
|
// even a long loginname it seems
|
||||||
|
$socket_filename = $socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['guid'] . '-' . $this->domain['id'] . '-php-fpm.socket';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$socket = strtolower(FileDir::makeCorrectFile($socket_filename));
|
||||||
|
|
||||||
if (!is_dir($socketdir) && $createifnotexists) {
|
if (!is_dir($socketdir) && $createifnotexists) {
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg($socketdir));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($socketdir));
|
||||||
|
|||||||
@@ -25,122 +25,84 @@
|
|||||||
|
|
||||||
namespace Froxlor\Cron\System;
|
namespace Froxlor\Cron\System;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\Cron\Forkable;
|
||||||
use Froxlor\Cron\FroxlorCron;
|
use Froxlor\Cron\FroxlorCron;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
|
|
||||||
class BackupCron extends FroxlorCron
|
class ExportCron extends FroxlorCron
|
||||||
{
|
{
|
||||||
|
use Forkable;
|
||||||
|
|
||||||
public static function run()
|
public static function run()
|
||||||
{
|
{
|
||||||
// Check Traffic-Lock
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'ExportCron: started - creating customer data export');
|
||||||
if (function_exists('pcntl_fork')) {
|
|
||||||
$BackupLock = FileDir::makeCorrectFile(dirname(self::getLockfile()) . "/froxlor_cron_backup.lock");
|
|
||||||
if (file_exists($BackupLock) && is_numeric($BackupPid = file_get_contents($BackupLock))) {
|
|
||||||
if (function_exists('posix_kill')) {
|
|
||||||
$BackupPidStatus = @posix_kill($BackupPid, 0);
|
|
||||||
} else {
|
|
||||||
system("kill -CHLD " . $BackupPid . " 1> /dev/null 2> /dev/null", $BackupPidStatus);
|
|
||||||
$BackupPidStatus = !$BackupPidStatus;
|
|
||||||
}
|
|
||||||
if ($BackupPidStatus) {
|
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Backup run already in progress');
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Create Backup Log and Fork
|
|
||||||
// We close the database - connection before we fork, so we don't share resources with the child
|
|
||||||
Database::needRoot(false); // this forces the connection to be set to null
|
|
||||||
$BackupPid = pcntl_fork();
|
|
||||||
// Parent
|
|
||||||
if ($BackupPid) {
|
|
||||||
file_put_contents($BackupLock, $BackupPid);
|
|
||||||
// unnecessary to recreate database connection here
|
|
||||||
return 0;
|
|
||||||
} elseif ($BackupPid == 0) {
|
|
||||||
// Child
|
|
||||||
posix_setsid();
|
|
||||||
// re-create db
|
|
||||||
Database::needRoot(false);
|
|
||||||
} else {
|
|
||||||
// Fork failed
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (extension_loaded('pcntl')) {
|
|
||||||
$msg = "PHP compiled with pcntl but pcntl_fork function is not available.";
|
|
||||||
} else {
|
|
||||||
$msg = "PHP compiled without pcntl.";
|
|
||||||
}
|
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, $msg . " Not forking backup-cron, this may take a long time!");
|
|
||||||
}
|
|
||||||
|
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'BackupCron: started - creating customer backup');
|
|
||||||
|
|
||||||
$result_tasks_stmt = Database::query("
|
$result_tasks_stmt = Database::query("
|
||||||
SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20' ORDER BY `id` ASC
|
SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20' ORDER BY `id` ASC
|
||||||
");
|
");
|
||||||
|
|
||||||
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :id");
|
|
||||||
|
|
||||||
$cronlog = FroxlorLogger::getInstanceOf();
|
|
||||||
$all_jobs = $result_tasks_stmt->fetchAll();
|
$all_jobs = $result_tasks_stmt->fetchAll();
|
||||||
foreach ($all_jobs as $row) {
|
|
||||||
if ($row['data'] != '') {
|
|
||||||
$row['data'] = json_decode($row['data'], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($row['data'])) {
|
if (!empty($all_jobs)) {
|
||||||
if (isset($row['data']['customerid']) && isset($row['data']['loginname']) && isset($row['data']['destdir'])) {
|
self::runFork([self::class, 'handle'], $all_jobs);
|
||||||
$row['data']['destdir'] = FileDir::makeCorrectDir($row['data']['destdir']);
|
|
||||||
$customerdocroot = FileDir::makeCorrectDir(Settings::Get('system.documentroot_prefix') . '/' . $row['data']['loginname'] . '/');
|
|
||||||
|
|
||||||
// create folder if not exists
|
|
||||||
if (!file_exists($row['data']['destdir']) && $row['data']['destdir'] != '/' && $row['data']['destdir'] != Settings::Get('system.documentroot_prefix') && $row['data']['destdir'] != $customerdocroot) {
|
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Creating backup-destination path for customer: ' . escapeshellarg($row['data']['destdir']));
|
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg($row['data']['destdir']));
|
|
||||||
}
|
|
||||||
|
|
||||||
self::createCustomerBackup($row['data'], $customerdocroot, $cronlog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove entry
|
|
||||||
Database::pexecute($del_stmt, [
|
|
||||||
'id' => $row['id']
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (function_exists('pcntl_fork')) {
|
|
||||||
@unlink($BackupLock);
|
|
||||||
die();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function handle(array $row)
|
||||||
|
{
|
||||||
|
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :id");
|
||||||
|
$cronlog = FroxlorLogger::getInstanceOf();
|
||||||
|
|
||||||
|
if ($row['data'] != '') {
|
||||||
|
$row['data'] = json_decode($row['data'], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($row['data'])) {
|
||||||
|
if (isset($row['data']['customerid']) && isset($row['data']['loginname']) && isset($row['data']['destdir'])) {
|
||||||
|
$row['data']['destdir'] = FileDir::makeCorrectDir($row['data']['destdir']);
|
||||||
|
$customerdocroot = FileDir::makeCorrectDir(Settings::Get('system.documentroot_prefix') . '/' . $row['data']['loginname'] . '/');
|
||||||
|
|
||||||
|
// create folder if not exists
|
||||||
|
if (!file_exists($row['data']['destdir']) && $row['data']['destdir'] != '/' && $row['data']['destdir'] != Settings::Get('system.documentroot_prefix') && $row['data']['destdir'] != $customerdocroot) {
|
||||||
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating data export destination path for customer: ' . escapeshellarg($row['data']['destdir']));
|
||||||
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($row['data']['destdir']));
|
||||||
|
}
|
||||||
|
|
||||||
|
self::createCustomerExport($row['data'], $customerdocroot, $cronlog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove entry
|
||||||
|
Database::pexecute($del_stmt, [
|
||||||
|
'id' => $row['id']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* depending on the give choice, the customers web-data, email-data and databases are being backup'ed
|
* depending on the give choice, the customers web-data, email-data and databases are being exported
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*
|
*
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private static function createCustomerBackup($data = null, $customerdocroot = null, &$cronlog = null)
|
private static function createCustomerExport($data = null, $customerdocroot = null, &$cronlog = null)
|
||||||
{
|
{
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating Backup for user "' . $data['loginname'] . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Creating data export for user "' . $data['loginname'] . '"');
|
||||||
|
|
||||||
// create tmp folder
|
// create tmp folder
|
||||||
$tmpdir = FileDir::makeCorrectDir($data['destdir'] . '/.tmp/');
|
$tmpdir = FileDir::makeCorrectDir($data['destdir'] . '/.tmp/');
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating tmp-folder "' . $tmpdir . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating tmp-folder "' . $tmpdir . '"');
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg($tmpdir));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg($tmpdir));
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
||||||
$create_backup_tar_data = "";
|
$create_export_tar_data = "";
|
||||||
|
|
||||||
// MySQL databases
|
// MySQL databases
|
||||||
if ($data['backup_dbs'] == 1) {
|
if ($data['dump_dbs'] == 1) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating mysql-folder "' . FileDir::makeCorrectDir($tmpdir . '/mysql') . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating mysql-folder "' . FileDir::makeCorrectDir($tmpdir . '/mysql') . '"');
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
|
||||||
@@ -152,7 +114,7 @@ class BackupCron extends FroxlorCron
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$has_dbs = false;
|
$has_dbs = false;
|
||||||
$current_dbserver = null;
|
$current_dbserver = -1;
|
||||||
while ($row = $sel_stmt->fetch()) {
|
while ($row = $sel_stmt->fetch()) {
|
||||||
// Get sql_root data for the specific database-server the database resides on
|
// Get sql_root data for the specific database-server the database resides on
|
||||||
if ($current_dbserver != $row['dbserver']) {
|
if ($current_dbserver != $row['dbserver']) {
|
||||||
@@ -180,16 +142,18 @@ class BackupCron extends FroxlorCron
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($has_dbs) {
|
if ($has_dbs) {
|
||||||
$create_backup_tar_data .= './mysql ';
|
$create_export_tar_data .= './mysql ';
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink($mysqlcnf_file);
|
if (file_exists($mysqlcnf_file)) {
|
||||||
|
unlink($mysqlcnf_file);
|
||||||
|
}
|
||||||
|
|
||||||
unset($sql_root);
|
unset($sql_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// E-mail data
|
// E-mail data
|
||||||
if ($data['backup_mail'] == 1) {
|
if ($data['dump_mail'] == 1) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating mail-folder "' . FileDir::makeCorrectDir($tmpdir . '/mail') . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating mail-folder "' . FileDir::makeCorrectDir($tmpdir . '/mail') . '"');
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mail')));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mail')));
|
||||||
|
|
||||||
@@ -209,28 +173,41 @@ class BackupCron extends FroxlorCron
|
|||||||
if (!empty($tar_file_list)) {
|
if (!empty($tar_file_list)) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfvz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfvz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
||||||
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
||||||
$create_backup_tar_data .= './mail ';
|
$create_export_tar_data .= './mail ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web data
|
// Web data
|
||||||
if ($data['backup_web'] == 1) {
|
if ($data['dump_web'] == 1) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating web-folder "' . FileDir::makeCorrectDir($tmpdir . '/web') . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating web-folder "' . FileDir::makeCorrectDir($tmpdir . '/web') . '"');
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/web')));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/web')));
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(FileDir::makeCorrectDir($tmpdir), 0, -1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(FileDir::makeCorrectDir($tmpdir), 0, -1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
|
||||||
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(FileDir::makeCorrectFile($tmpdir), 0, -1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
|
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(FileDir::makeCorrectFile($tmpdir), 0, -1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
|
||||||
$create_backup_tar_data .= './web ';
|
$create_export_tar_data .= './web ';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($create_backup_tar_data)) {
|
if (!empty($create_export_tar_data)) {
|
||||||
$backup_file = FileDir::makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-backup_' . date('YmdHi', time()) . '.tar.gz');
|
// set owner to customer
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating backup-file "' . $backup_file . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> chown -R ' . (int)$data['uid'] . ':' . (int)$data['gid'] . ' ' . escapeshellarg($tmpdir));
|
||||||
// pack all archives in tmp-dir to one
|
FileDir::safe_exec('chown -R ' . (int)$data['uid'] . ':' . (int)$data['gid'] . ' ' . escapeshellarg($tmpdir));
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg($backup_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_backup_tar_data));
|
// create tar-file
|
||||||
FileDir::safe_exec('tar cfz ' . escapeshellarg($backup_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_backup_tar_data));
|
$export_file = FileDir::makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-export_' . date('YmdHi', time()) . '.tar.gz' . (!empty($data['pgp_public_key']) ? '.gpg' : ''));
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating export-file "' . $export_file . '"');
|
||||||
|
if (!empty($data['pgp_public_key'])) {
|
||||||
|
// pack all archives in tmp-dir to one archive and encrypt it with gpg
|
||||||
|
$recipient_file = FileDir::makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-recipients.gpg');
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating recipient-file "' . $recipient_file . '"');
|
||||||
|
file_put_contents($recipient_file, $data['pgp_public_key']);
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz - -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data) . ' | gpg --encrypt --recipient-file ' . escapeshellarg($recipient_file) . ' --output ' . escapeshellarg($export_file) . ' --trust-model always --batch --yes');
|
||||||
|
FileDir::safe_exec('tar cfz - -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data) . ' | gpg --encrypt --recipient-file ' . escapeshellarg($recipient_file) . ' --output ' . escapeshellarg($export_file) . ' --trust-model always --batch --yes', $return_value, ['|']);
|
||||||
|
} else {
|
||||||
|
// pack all archives in tmp-dir to one archive
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg($export_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data));
|
||||||
|
FileDir::safe_exec('tar cfz ' . escapeshellarg($export_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data));
|
||||||
|
}
|
||||||
// move to destination directory
|
// move to destination directory
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mv ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($data['destdir']));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mv ' . escapeshellarg($export_file) . ' ' . escapeshellarg($data['destdir']));
|
||||||
FileDir::safe_exec('mv ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($data['destdir']));
|
FileDir::safe_exec('mv ' . escapeshellarg($export_file) . ' ' . escapeshellarg($data['destdir']));
|
||||||
// remove tmp-files
|
// remove tmp-files
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> rm -rf ' . escapeshellarg($tmpdir));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> rm -rf ' . escapeshellarg($tmpdir));
|
||||||
FileDir::safe_exec('rm -rf ' . escapeshellarg($tmpdir));
|
FileDir::safe_exec('rm -rf ' . escapeshellarg($tmpdir));
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user