Compare commits

..

31 Commits

Author SHA1 Message Date
Michael Kaufmann
8cf3f4ee24 set version to 0.10.26 for upcoming maintenance releasae
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-05-14 08:21:53 +02:00
Michael Kaufmann
e83f7634f8 Merge pull request #938 from Froxlor/dependabot/composer/phpmailer/phpmailer-6.4.1
Bump phpmailer/phpmailer from 6.2.0 to 6.4.1
2021-05-04 19:57:10 +02:00
dependabot[bot]
6eb6595a46 Bump phpmailer/phpmailer from 6.2.0 to 6.4.1
Bumps [phpmailer/phpmailer](https://github.com/PHPMailer/PHPMailer) from 6.2.0 to 6.4.1.
- [Release notes](https://github.com/PHPMailer/PHPMailer/releases)
- [Changelog](https://github.com/PHPMailer/PHPMailer/blob/master/changelog.md)
- [Commits](https://github.com/PHPMailer/PHPMailer/compare/v6.2.0...v6.4.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-04 17:43:20 +00:00
Michael Kaufmann
bd48fb7328 catch exception of password-complexity check when changing account password; fixes #935
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-04-14 08:59:44 +02:00
Michael Kaufmann
769525bb56 do not touch/chown error/access log if log is disabled, fixes #934
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-04-12 09:42:25 +02:00
Michael Kaufmann
9195fb3c98 additionally sort by length of username for libnss-extrausers passwd file to have the main user as first in result in any case; fixes #933
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-04-12 09:37:36 +02:00
Michael Kaufmann
82922f7aea add new settings for legal-notes; terms-of-use and privacy-policy; fixes #930
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-24 14:36:48 +01:00
Michael Kaufmann
db1a39b6d9 match composePhpOptions() definition everywhere
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-24 13:49:58 +01:00
Michael Kaufmann
7fbbc2ea0b add vhost replacer {FPMSOCKET} for custom vhost configs; fixes #931
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-24 13:46:24 +01:00
Michael Kaufmann
91d4432108 check rr against possible existing CNAME entries, fixes #927
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-15 17:33:30 +01:00
Michael Kaufmann
c8914312aa Refactoring columns from large table to avoid '1118 Row size too large' error
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-11 09:45:52 +01:00
Michael Kaufmann
3fd89c48e8 set version to 0.10.25 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-05 20:27:55 +01:00
Michael Kaufmann
eceb144a77 also trigger removal of domain in powerdns database if used; refs #923
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-04 12:09:03 +01:00
Michael Kaufmann
1d9651b18a trgger acme.sh removal for domains if customers is being deleted; fixes #923
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-04 12:07:20 +01:00
Michael Kaufmann
49db4e60cb escape passwords for email content (new email-account, new ftp-account and new database); fixes #905
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-03 11:25:58 +01:00
Michael Kaufmann
53e8ccbccb added 'deactivated' parameter to EmailAccounts.update() so admins can disable individual email-accounts, will be overridden if customer is deactivatd and re-enabled; fixes #921
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-03 10:59:16 +01:00
Michael Kaufmann
6d8fc215f1 add description field to panel_domains and mail_virtual table, API parameter 'description' for Domains.add()/Domains.update() and Email.add()/Emails.update(); fixes #910
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-03 10:25:42 +01:00
Michael Kaufmann
f94c303cb3 add API parameter 'show_usages' for Customers.listing() and Customers.get() to return number of domains, and diskspaced used split into webspace_used, mailspace_used and dbspace_used; fixes #912
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-03-03 09:50:30 +01:00
Michael Kaufmann
2be1873354 fix frontend issue with displaying correct options in domain listing when using php8, thx to cscholz
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-02-24 19:56:26 +01:00
Michael Kaufmann
d1d36c32fe Merge pull request #920 from RipClaw2971/patch-1
lowercase domain names for ssl-certificate file check (fallback)
2021-02-24 13:07:26 +01:00
RipClaw2971
3b3527348f Update AcmeSh.php
Renewed certificates are not recognized if the domain is in upper/lower case.
2021-02-24 13:00:31 +01:00
Michael Kaufmann
036d5f0713 Merge pull request #919 from nachtgeist/soa
dns: make mail address of SOA records configurable
2021-02-21 18:27:57 +01:00
Daniel Reichelt
a1b8807b0f dns: make mail address of SOA records configurable 2021-02-21 13:00:30 +01:00
Michael Kaufmann
356a087b6a Merge pull request #918 from nachtgeist/pns
dns: check NS entry to be used as primary NS
2021-02-21 09:14:37 +01:00
Michael Kaufmann
0a77fd7150 Merge pull request #917 from nachtgeist/pw
system: validatePassword(): also quote the delimiter ('/')
2021-02-21 09:13:02 +01:00
Daniel Reichelt
67d67a287f system: validatePassword(): also quote the delimiter ('/')
Quoting the default regex delimiter is required for the password
complexity check to work if '/' had been specified as special character
in Froxlor's account settings.
2021-02-21 02:33:46 +01:00
Daniel Reichelt
1f792466bf dns: check NS entry to be used as primary NS
Don't just blindly use the first custom NS entry for SOA, actually check
if it pertains to the domain in question
2021-02-21 02:33:23 +01:00
Michael Kaufmann
5a6343b47c php8 compatibility, fixes #916
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-02-16 12:38:01 +01:00
Michael Kaufmann
841c529107 fix check for required firstname/name/company in Customers.update(), fixes #915
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-02-15 23:26:18 +01:00
Michael Kaufmann
41c3f21f0b list only phpenabled and http-enabled domains in php-configuration overview; fixes #911
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-02-11 16:16:04 +01:00
Michael Kaufmann
b8c0688ba0 added possibility to use 'in' sql-operation in sql_where parameter for Api-calls; php-8 compat fix in admin_traffic
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2021-02-11 12:09:42 +01:00
41 changed files with 550 additions and 126 deletions

View File

@@ -265,7 +265,37 @@ return array(
'traffic.mail' => $lng['menue']['traffic']['traffic'] . " / Mail" 'traffic.mail' => $lng['menue']['traffic']['traffic'] . " / Mail"
), ),
'save_method' => 'storeSettingField' 'save_method' => 'storeSettingField'
) ),
'panel_imprint_url' => array(
'label' => $lng['serversettings']['imprint_url'],
'settinggroup' => 'panel',
'varname' => 'imprint_url',
'type' => 'string',
'string_type' => 'url',
'string_emptyallowed' => true,
'default' => '',
'save_method' => 'storeSettingField'
),
'panel_terms_url' => array(
'label' => $lng['serversettings']['terms_url'],
'settinggroup' => 'panel',
'varname' => 'terms_url',
'type' => 'string',
'string_type' => 'url',
'string_emptyallowed' => true,
'default' => '',
'save_method' => 'storeSettingField'
),
'panel_privacy_url' => array(
'label' => $lng['serversettings']['privacy_url'],
'settinggroup' => 'panel',
'varname' => 'privacy_url',
'type' => 'string',
'string_type' => 'url',
'string_emptyallowed' => true,
'default' => '',
'save_method' => 'storeSettingField'
),
) )
) )
) )

View File

@@ -132,6 +132,16 @@ return array(
'int_min' => 3600, /* 1 hour */ 'int_min' => 3600, /* 1 hour */
'int_max' => 2147483647, /* integer max */ 'int_max' => 2147483647, /* integer max */
'save_method' => 'storeSettingField' 'save_method' => 'storeSettingField'
),
'system_soaemail' => array(
'label' => $lng['serversettings']['soaemail'],
'settinggroup' => 'system',
'varname' => 'soaemail',
'type' => 'string',
'string_type' => 'mail',
'string_emptyallowed' => true,
'default' => '',
'save_method' => 'storeSettingField'
) )
) )
) )

View File

@@ -193,8 +193,12 @@ if ($page == 'overview') {
\Froxlor\UI\Response::standard_error('oldpasswordnotcorrect'); \Froxlor\UI\Response::standard_error('oldpasswordnotcorrect');
} }
$new_password = \Froxlor\Validate\Validate::validate($_POST['new_password'], 'new password'); try {
$new_password_confirm = \Froxlor\Validate\Validate::validate($_POST['new_password_confirm'], 'new password confirm'); $new_password = \Froxlor\System\Crypt::validatePassword($_POST['new_password'], 'new password');
$new_password_confirm = \Froxlor\System\Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
if ($old_password == '') { if ($old_password == '') {
\Froxlor\UI\Response::standard_error(array( \Froxlor\UI\Response::standard_error(array(

View File

@@ -56,6 +56,26 @@ if ($page == 'overview' || $page == 'customers') {
$maxyears = date("Y") - $minyear['year']; $maxyears = date("Y") - $minyear['year'];
} }
$params = [];
if ($userinfo['customers_see_all'] == '0') {
$params = [
'id' => $userinfo['adminid']
];
}
$customer_name_list_stmt = Database::prepare("
SELECT `customerid`,`company`,`name`,`firstname`
FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE `deactivated`='0'" . ($userinfo['customers_see_all'] ? '' : " AND `adminid` = :id") . "
ORDER BY name"
);
$traffic_list_stmt = Database::prepare("
SELECT month, SUM(http+ftp_up+ftp_down+mail)*1024 AS traffic
FROM `" . TABLE_PANEL_TRAFFIC . "`
WHERE year = :year AND `customerid` = :id
GROUP BY month ORDER BY month"
);
for ($years = 0; $years <= $maxyears; $years ++) { for ($years = 0; $years <= $maxyears; $years ++) {
$overview['year'] = date("Y") - $years; $overview['year'] = date("Y") - $years;
@@ -76,14 +96,7 @@ if ($page == 'overview' || $page == 'customers') {
'dec' => 0 'dec' => 0
); );
$customer_name_list_stmt = Database::prepare(" Database::pexecute($customer_name_list_stmt, $params);
SELECT `customerid`,`company`,`name`,`firstname`
FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE `deactivated`='0'" . ($userinfo['customers_see_all'] ? '' : " AND `adminid` = :id") . "
ORDER BY name");
Database::pexecute($customer_name_list_stmt, array(
'id' => $userinfo['adminid']
));
while ($customer_name = $customer_name_list_stmt->fetch(PDO::FETCH_ASSOC)) { while ($customer_name = $customer_name_list_stmt->fetch(PDO::FETCH_ASSOC)) {
@@ -104,11 +117,6 @@ if ($page == 'overview' || $page == 'customers') {
'dec' => '-' 'dec' => '-'
); );
$traffic_list_stmt = Database::prepare("
SELECT month, SUM(http+ftp_up+ftp_down+mail)*1024 AS traffic
FROM `" . TABLE_PANEL_TRAFFIC . "`
WHERE year = :year AND `customerid` = :id
GROUP BY month ORDER BY month");
Database::pexecute($traffic_list_stmt, array( Database::pexecute($traffic_list_stmt, array(
'year' => (date("Y") - $years), 'year' => (date("Y") - $years),
'id' => $customer_name['customerid'] 'id' => $customer_name['customerid']

14
composer.lock generated
View File

@@ -150,16 +150,16 @@
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.2.0", "version": "v6.4.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "e38888a75c070304ca5514197d4847a59a5c853f" "reference": "9256f12d8fb0cd0500f93b19e18c356906cbed3d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/e38888a75c070304ca5514197d4847a59a5c853f", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/9256f12d8fb0cd0500f93b19e18c356906cbed3d",
"reference": "e38888a75c070304ca5514197d4847a59a5c853f", "reference": "9256f12d8fb0cd0500f93b19e18c356906cbed3d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -177,7 +177,7 @@
"yoast/phpunit-polyfills": "^0.2.0" "yoast/phpunit-polyfills": "^0.2.0"
}, },
"suggest": { "suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset", "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication", "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging", "psr/log": "For optional PSR-3 debug logging",
@@ -214,7 +214,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP", "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": { "support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues", "issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.2.0" "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.4.1"
}, },
"funding": [ "funding": [
{ {
@@ -222,7 +222,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2020-11-25T15:24:57+00:00" "time": "2021-04-29T12:25:04+00:00"
}, },
{ {
"name": "psr/log", "name": "psr/log",

View File

@@ -136,14 +136,20 @@ if ($page == 'overview') {
eval("echo \"" . \Froxlor\UI\Template::getTemplate('index/index') . "\";"); eval("echo \"" . \Froxlor\UI\Template::getTemplate('index/index') . "\";");
} elseif ($page == 'change_password') { } elseif ($page == 'change_password') {
if (isset($_POST['send']) && $_POST['send'] == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$old_password = \Froxlor\Validate\Validate::validate($_POST['old_password'], 'old password'); $old_password = \Froxlor\Validate\Validate::validate($_POST['old_password'], 'old password');
if (! \Froxlor\System\Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) { if (! \Froxlor\System\Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) {
\Froxlor\UI\Response::standard_error('oldpasswordnotcorrect'); \Froxlor\UI\Response::standard_error('oldpasswordnotcorrect');
} }
$new_password = \Froxlor\System\Crypt::validatePassword($_POST['new_password'], 'new password'); try {
$new_password_confirm = \Froxlor\System\Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm'); $new_password = \Froxlor\System\Crypt::validatePassword($_POST['new_password'], 'new password');
$new_password_confirm = \Froxlor\System\Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
if ($old_password == '') { if ($old_password == '') {
\Froxlor\UI\Response::standard_error(array( \Froxlor\UI\Response::standard_error(array(

View File

@@ -114,7 +114,7 @@ if ($action == '2fa_entercode') {
)); ));
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row['customer'] == $loginname) { if ($row && $row['customer'] == $loginname) {
$table = "`" . TABLE_PANEL_CUSTOMERS . "`"; $table = "`" . TABLE_PANEL_CUSTOMERS . "`";
$uid = 'customerid'; $uid = 'customerid';
$adminsession = '0'; $adminsession = '0';
@@ -142,7 +142,7 @@ if ($action == '2fa_entercode') {
"loginname" => $loginname "loginname" => $loginname
)); ));
$row3 = $stmt->fetch(PDO::FETCH_ASSOC); $row3 = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row3['customer'] == $loginname) { if ($row3 && $row3['customer'] == $loginname) {
$table = "`" . TABLE_PANEL_CUSTOMERS . "`"; $table = "`" . TABLE_PANEL_CUSTOMERS . "`";
$uid = 'customerid'; $uid = 'customerid';
$adminsession = '0'; $adminsession = '0';
@@ -181,7 +181,7 @@ if ($action == '2fa_entercode') {
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
} }
if ($row['admin'] == $loginname) { if ($row && $row['admin'] == $loginname) {
$table = "`" . TABLE_PANEL_ADMINS . "`"; $table = "`" . TABLE_PANEL_ADMINS . "`";
$uid = 'adminid'; $uid = 'adminid';
$adminsession = '1'; $adminsession = '1';

View File

@@ -71,6 +71,7 @@ CREATE TABLE `mail_virtual` (
`customerid` int(11) NOT NULL default '0', `customerid` int(11) NOT NULL default '0',
`popaccountid` int(11) NOT NULL default '0', `popaccountid` int(11) NOT NULL default '0',
`iscatchall` tinyint(1) unsigned NOT NULL default '0', `iscatchall` tinyint(1) unsigned NOT NULL default '0',
`description` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `email` (`email`) KEY `email` (`email`)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci; ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
@@ -269,12 +270,13 @@ CREATE TABLE `panel_domains` (
`writeaccesslog` tinyint(1) DEFAULT '1', `writeaccesslog` tinyint(1) DEFAULT '1',
`writeerrorlog` tinyint(1) DEFAULT '1', `writeerrorlog` tinyint(1) DEFAULT '1',
`override_tls` tinyint(1) DEFAULT '0', `override_tls` tinyint(1) DEFAULT '0',
`ssl_protocols` text, `ssl_protocols` varchar(255) NOT NULL DEFAULT '',
`ssl_cipher_list` text, `ssl_cipher_list` varchar(500) NOT NULL DEFAULT '',
`tlsv13_cipher_list` text, `tlsv13_cipher_list` varchar(500) NOT NULL DEFAULT '',
`ssl_enabled` tinyint(1) DEFAULT '1', `ssl_enabled` tinyint(1) DEFAULT '1',
`ssl_honorcipherorder` tinyint(1) DEFAULT '0', `ssl_honorcipherorder` tinyint(1) DEFAULT '0',
`ssl_sessiontickets` tinyint(1) DEFAULT '1', `ssl_sessiontickets` tinyint(1) DEFAULT '1',
`description` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `customerid` (`customerid`), KEY `customerid` (`customerid`),
KEY `parentdomain` (`parentdomainid`), KEY `parentdomain` (`parentdomainid`),
@@ -674,6 +676,7 @@ opcache.interned_strings_buffer'),
('system', 'apply_phpconfigs_default', '1'), ('system', 'apply_phpconfigs_default', '1'),
('system', 'hide_incompatible_settings', '0'), ('system', 'hide_incompatible_settings', '0'),
('system', 'include_default_vhostconf', '0'), ('system', 'include_default_vhostconf', '0'),
('system', 'soaemail', ''),
('api', 'enabled', '0'), ('api', 'enabled', '0'),
('2fa', 'enabled', '1'), ('2fa', 'enabled', '1'),
('panel', 'decimal_places', '4'), ('panel', 'decimal_places', '4'),
@@ -708,8 +711,11 @@ opcache.interned_strings_buffer'),
('panel', 'password_special_char', '!?<>§$%+#=@'), ('panel', 'password_special_char', '!?<>§$%+#=@'),
('panel', 'customer_hide_options', ''), ('panel', 'customer_hide_options', ''),
('panel', 'is_configured', '0'), ('panel', 'is_configured', '0'),
('panel', 'version', '0.10.24'), ('panel', 'imprint_url', ''),
('panel', 'db_version', '202101200'); ('panel', 'terms_url', ''),
('panel', 'privacy_url', ''),
('panel', 'version', '0.10.26'),
('panel', 'db_version', '202103240');
DROP TABLE IF EXISTS `panel_tasks`; DROP TABLE IF EXISTS `panel_tasks`;

View File

@@ -725,3 +725,81 @@ if (\Froxlor\Froxlor::isFroxlorVersion('0.10.23.1')) {
showUpdateStep("Updating from 0.10.23.1 to 0.10.24", false); showUpdateStep("Updating from 0.10.23.1 to 0.10.24", false);
\Froxlor\Froxlor::updateToVersion('0.10.24'); \Froxlor\Froxlor::updateToVersion('0.10.24');
} }
if (\Froxlor\Froxlor::isDatabaseVersion('202101200')) {
showUpdateStep("Adding setting for mail address used in SOA records", true);
Settings::AddNew("system.soaemail", '');
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('202102200');
}
/*
* skip due to potential "1118 Row size too large" error
*
if (\Froxlor\Froxlor::isDatabaseVersion('202102200')) {
showUpdateStep("Add new description fields to mail and domain table", true);
Database::query("ALTER TABLE panel_domains ADD `description` varchar(255) NOT NULL DEFAULT '' AFTER `ssl_sessiontickets`;");
Database::query("ALTER TABLE mail_virtual ADD `description` varchar(255) NOT NULL DEFAULT '' AFTER `iscatchall`");
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('202103030');
}
*/
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.24')) {
showUpdateStep("Updating from 0.10.24 to 0.10.25", false);
\Froxlor\Froxlor::updateToVersion('0.10.25');
}
if (\Froxlor\Froxlor::isDatabaseVersion('202102200') || \Froxlor\Froxlor::isDatabaseVersion('202103030')) {
showUpdateStep("Refactoring columns from large tables", true);
Database::query("ALTER TABLE panel_domains CHANGE `ssl_protocols` `ssl_protocols` varchar(255) NOT NULL DEFAULT '';");
Database::query("ALTER TABLE panel_domains CHANGE `ssl_cipher_list` `ssl_cipher_list` varchar(500) NOT NULL DEFAULT '';");
Database::query("ALTER TABLE panel_domains CHANGE `tlsv13_cipher_list` `tlsv13_cipher_list` varchar(500) NOT NULL DEFAULT '';");
lastStepStatus(0);
showUpdateStep("Add new description fields to mail and domain table", true);
$result = Database::query("DESCRIBE `panel_domains`");
$columnfound = 0;
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
if ($row['Field'] == 'description') {
$columnfound = 1;
}
}
if (! $columnfound) {
Database::query("ALTER TABLE panel_domains ADD `description` varchar(255) NOT NULL DEFAULT '' AFTER `ssl_sessiontickets`;");
}
$result = Database::query("DESCRIBE `mail_virtual`");
$columnfound = 0;
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
if ($row['Field'] == 'description') {
$columnfound = 1;
}
}
if (! $columnfound) {
Database::query("ALTER TABLE mail_virtual ADD `description` varchar(255) NOT NULL DEFAULT '' AFTER `iscatchall`");
}
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('202103110');
}
if (\Froxlor\Froxlor::isDatabaseVersion('202103110')) {
showUpdateStep("Adding settings for imprint, terms of use and privacy policy URLs", true);
Settings::AddNew("panel.imprint_url", '');
Settings::AddNew("panel.terms_url", '');
Settings::AddNew("panel.privacy_url", '');
lastStepStatus(0);
\Froxlor\Froxlor::updateToDbVersion('202103240');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.25')) {
showUpdateStep("Updating from 0.10.25 to 0.10.26", false);
\Froxlor\Froxlor::updateToVersion('0.10.26');
}

View File

@@ -310,6 +310,13 @@ abstract class ApiCommand extends ApiParameter
} elseif (in_array($valoper['op'], $ops)) { } elseif (in_array($valoper['op'], $ops)) {
$condition .= $field . ' ' . $valoper['op'] . ':' . $cleanfield; $condition .= $field . ' ' . $valoper['op'] . ':' . $cleanfield;
$query_fields[':' . $cleanfield] = $valoper['value'] ?? ''; $query_fields[':' . $cleanfield] = $valoper['value'] ?? '';
} elseif (strtolower($valoper['op']) == 'in' && is_array($valoper['value']) && count($valoper['value']) > 0) {
$condition .= $field . ' ' . $valoper['op'] . ' (';
foreach ($valoper['value'] as $incnt => $invalue) {
$condition .= ":" . $cleanfield . $incnt . ", ";
$query_fields[':' . $cleanfield . $incnt] = $invalue ?? '';
}
$condition = substr($condition, 0, - 2) . ')';
} else { } else {
continue; continue;
} }
@@ -518,7 +525,7 @@ abstract class ApiCommand extends ApiParameter
$customer_ids[] = $customer['customerid']; $customer_ids[] = $customer['customerid'];
} }
} else { } else {
if (!$this->isInternal() && ! empty($customer_hide_option) && \Froxlor\Settings::IsInList('panel.customer_hide_options', $customer_hide_option)) { if (! $this->isInternal() && ! empty($customer_hide_option) && \Froxlor\Settings::IsInList('panel.customer_hide_options', $customer_hide_option)) {
throw new \Exception("You cannot access this resource", 405); throw new \Exception("You cannot access this resource", 405);
} }
$customer_ids = array( $customer_ids = array(

View File

@@ -33,7 +33,9 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
* optional specify offset for resultset * optional specify offset for resultset
* @param array $sql_orderby * @param array $sql_orderby
* optional array with index = fieldname and value = ASC|DESC to order the resultset by one or more fields * optional array with index = fieldname and value = ASC|DESC to order the resultset by one or more fields
* * @param bool $show_usages
* optional, default false
*
* @access admin * @access admin
* @throws \Exception * @throws \Exception
* @return string json-encoded array count|list * @return string json-encoded array count|list
@@ -41,6 +43,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
public function listing() public function listing()
{ {
if ($this->isAdmin()) { if ($this->isAdmin()) {
$show_usages = $this->getBoolParam('show_usages', true, false);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list customers"); $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list customers");
$query_fields = array(); $query_fields = array();
$result_stmt = Database::prepare(" $result_stmt = Database::prepare("
@@ -57,7 +60,47 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$params = array_merge($params, $query_fields); $params = array_merge($params, $query_fields);
Database::pexecute($result_stmt, $params, true, true); Database::pexecute($result_stmt, $params, true, true);
$result = array(); $result = array();
$domains_stmt = null;
$usages_stmt = null;
if ($show_usages) {
$domains_stmt = Database::prepare("
SELECT COUNT(`id`) AS `domains`
FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `customerid` = :cid
AND `parentdomainid` = '0'
AND `id`<> :stdd
");
$usages_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_DISKSPACE . "`
WHERE `customerid` = :cid
ORDER BY `stamp` DESC LIMIT 1
");
}
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) { while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
if ($show_usages) {
// get number of domains
Database::pexecute($domains_stmt, array(
'cid' => $row['customerid'],
'stdd' => $row['standardsubdomain']
));
$domains = $domains_stmt->fetch(\PDO::FETCH_ASSOC);
$row['domains'] = intval($domains['domains']);
// get disk-space usages for web, mysql and mail
$usages = Database::pexecute_first($usages_stmt, array(
'cid' => $row['customerid']
));
if ($usages) {
$row['webspace_used'] = $usages['webspace'];
$row['mailspace_used'] = $usages['mail'];
$row['dbspace_used'] = $usages['mysql'];
} else {
$row['webspace_used'] = 0;
$row['mailspace_used'] = 0;
$row['dbspace_used'] = 0;
}
}
$result[] = $row; $result[] = $row;
} }
return $this->response(200, "successful", array( return $this->response(200, "successful", array(
@@ -103,6 +146,8 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
* optional, the customer-id * optional, the customer-id
* @param string $loginname * @param string $loginname
* optional, the loginname * optional, the loginname
* @param bool $show_usages
* optional, default false
* *
* @access admin, customer * @access admin, customer
* @throws \Exception * @throws \Exception
@@ -113,6 +158,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$id = $this->getParam('id', true, 0); $id = $this->getParam('id', true, 0);
$ln_optional = ($id <= 0 ? false : true); $ln_optional = ($id <= 0 ? false : true);
$loginname = $this->getParam('loginname', $ln_optional, ''); $loginname = $this->getParam('loginname', $ln_optional, '');
$show_usages = $this->getBoolParam('show_usages', true, false);
if ($this->isAdmin()) { if ($this->isAdmin()) {
$result_stmt = Database::prepare(" $result_stmt = Database::prepare("
@@ -142,6 +188,40 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
if (! $this->isAdmin() && $result['custom_notes_show'] != 1) { if (! $this->isAdmin() && $result['custom_notes_show'] != 1) {
$result['custom_notes'] = ""; $result['custom_notes'] = "";
} }
if ($show_usages) {
// get number of domains
$domains_stmt = Database::prepare("
SELECT COUNT(`id`) AS `domains`
FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `customerid` = :cid
AND `parentdomainid` = '0'
AND `id`<> :stdd
");
Database::pexecute($domains_stmt, array(
'cid' => $result['customerid'],
'stdd' => $result['standardsubdomain']
));
$domains = $domains_stmt->fetch(\PDO::FETCH_ASSOC);
$result['domains'] = intval($domains['domains']);
// get disk-space usages for web, mysql and mail
$usages_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_DISKSPACE . "`
WHERE `customerid` = :cid
ORDER BY `stamp` DESC LIMIT 1
");
$usages = Database::pexecute_first($usages_stmt, array(
'cid' => $result['customerid']
));
if ($usages) {
$result['webspace_used'] = $usages['webspace'];
$result['mailspace_used'] = $usages['mail'];
$result['dbspace_used'] = $usages['mysql'];
} else {
$result['webspace_used'] = 0;
$result['mailspace_used'] = 0;
$result['dbspace_used'] = 0;
}
}
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get customer '" . $result['loginname'] . "'"); $this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get customer '" . $result['loginname'] . "'");
return $this->response(200, "successful", $result); return $this->response(200, "successful", $result);
} }
@@ -873,7 +953,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$email = $this->getParam('email', true, $idna_convert->decode($result['email'])); $email = $this->getParam('email', true, $idna_convert->decode($result['email']));
$name = $this->getParam('name', true, $result['name']); $name = $this->getParam('name', true, $result['name']);
$firstname = $this->getParam('firstname', true, $result['firstname']); $firstname = $this->getParam('firstname', true, $result['firstname']);
$company_required = (! empty($name) && empty($firstname)) || (empty($name) && ! empty($firstname)) || (empty($name) && empty($firstname)); $company_required = empty($result['company']) && ((! empty($name) && empty($firstname)) || (empty($name) && ! empty($firstname)) || (empty($name) && empty($firstname)));
$company = $this->getParam('company', ($company_required ? false : true), $result['company']); $company = $this->getParam('company', ($company_required ? false : true), $result['company']);
$street = $this->getParam('street', true, $result['street']); $street = $this->getParam('street', true, $result['street']);
$zipcode = $this->getParam('zipcode', true, $result['zipcode']); $zipcode = $this->getParam('zipcode', true, $result['zipcode']);
@@ -1411,7 +1491,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
), true, true); ), true, true);
// first gather all domain-id's to clean up panel_domaintoip, dns-entries and certificates accordingly // first gather all domain-id's to clean up panel_domaintoip, dns-entries and certificates accordingly
$did_stmt = Database::prepare("SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `customerid` = :id"); $did_stmt = Database::prepare("SELECT `id`, `domain` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `customerid` = :id");
Database::pexecute($did_stmt, array( Database::pexecute($did_stmt, array(
'id' => $id 'id' => $id
), true, true); ), true, true);
@@ -1431,6 +1511,10 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
Database::pexecute($stmt, array( Database::pexecute($stmt, array(
'did' => $row['id'] 'did' => $row['id']
), true, true); ), true, true);
// remove domains DNS from powerDNS if used, #581
\Froxlor\System\Cronjob::inserttask('11', $result['domain']);
// remove domain from acme.sh / lets encrypt if used
\Froxlor\System\Cronjob::inserttask('12', $row['domain']);
} }
// remove customer domains // remove customer domains
$stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `customerid` = :id"); $stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `customerid` = :id");

View File

@@ -136,8 +136,24 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
// types // types
if ($type == 'A' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) { if ($type == 'A' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) {
$errors[] = $this->lng['error']['dns_arec_noipv4']; $errors[] = $this->lng['error']['dns_arec_noipv4'];
} elseif ($type == 'A') {
// check whether there is a CNAME-record for the same resource
foreach ($dom_entries as $existing_entries) {
if ($existing_entries['type'] == 'CNAME' && $existing_entries['record'] == $record) {
$errors[] = $this->lng['error']['dns_other_nomorerr'];
break;
}
}
} elseif ($type == 'AAAA' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { } elseif ($type == 'AAAA' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
$errors[] = $this->lng['error']['dns_aaaarec_noipv6']; $errors[] = $this->lng['error']['dns_aaaarec_noipv6'];
} elseif ($type == 'AAAA') {
// check whether there is a CNAME-record for the same resource
foreach ($dom_entries as $existing_entries) {
if ($existing_entries['type'] == 'CNAME' && $existing_entries['record'] == $record) {
$errors[] = $this->lng['error']['dns_other_nomorerr'];
break;
}
}
} elseif ($type == 'CAA' && ! empty($content)) { } elseif ($type == 'CAA' && ! empty($content)) {
$re = '/(?\'critical\'\d)\h*(?\'type\'iodef|issue|issuewild)\h*(?\'value\'(?\'issuevalue\'"(?\'domain\'(?=.{3,128}$)(?>(?>[a-zA-Z0-9]+[a-zA-Z0-9-]*[a-zA-Z0-9]+|[a-zA-Z0-9]+)\.)*(?>[a-zA-Z]{2,}|[a-zA-Z0-9]{2,}\.[a-zA-Z]{2,}))[;\h]*(?\'parameters\'(?>[a-zA-Z0-9]{1,60}=[a-zA-Z0-9]{1,60}\h*)+)?")|(?\'iodefvalue\'"(?\'url\'(mailto:.*|http:\/\/.*|https:\/\/.*))"))/'; $re = '/(?\'critical\'\d)\h*(?\'type\'iodef|issue|issuewild)\h*(?\'value\'(?\'issuevalue\'"(?\'domain\'(?=.{3,128}$)(?>(?>[a-zA-Z0-9]+[a-zA-Z0-9-]*[a-zA-Z0-9]+|[a-zA-Z0-9]+)\.)*(?>[a-zA-Z]{2,}|[a-zA-Z0-9]{2,}\.[a-zA-Z]{2,}))[;\h]*(?\'parameters\'(?>[a-zA-Z0-9]{1,60}=[a-zA-Z0-9]{1,60}\h*)+)?")|(?\'iodefvalue\'"(?\'url\'(mailto:.*|http:\/\/.*|https:\/\/.*))"))/';
preg_match($re, $content, $matches); preg_match($re, $content, $matches);
@@ -198,6 +214,10 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$errors[] = $this->lng['error']['dns_mx_noalias']; $errors[] = $this->lng['error']['dns_mx_noalias'];
break; break;
} }
elseif ($existing_entries['type'] == 'CNAME' && $existing_entries['record'] == $record) {
$errors[] = $this->lng['error']['dns_other_nomorerr'];
break;
}
} }
} }
// append trailing dot (again) // append trailing dot (again)
@@ -210,6 +230,14 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
} }
if (! \Froxlor\Validate\Validate::validateDomain($content)) { if (! \Froxlor\Validate\Validate::validateDomain($content)) {
$errors[] = $this->lng['error']['dns_ns_invaliddom']; $errors[] = $this->lng['error']['dns_ns_invaliddom'];
} else {
// check whether there is a CNAME-record for the same resource
foreach ($dom_entries as $existing_entries) {
if ($existing_entries['type'] == 'CNAME' && $existing_entries['record'] == $record) {
$errors[] = $this->lng['error']['dns_other_nomorerr'];
break;
}
}
} }
// append trailing dot (again) // append trailing dot (again)
$content .= '.'; $content .= '.';

View File

@@ -288,6 +288,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
* optional list of allowed/used ssl/tls ciphers, see system.ssl_cipher_list setting, only used/required if $override_tls is true, default empty or system.ssl_cipher_list setting if $override_tls is true * optional list of allowed/used ssl/tls ciphers, see system.ssl_cipher_list setting, only used/required if $override_tls is true, default empty or system.ssl_cipher_list setting if $override_tls is true
* @param string $tlsv13_cipher_list * @param string $tlsv13_cipher_list
* optional list of allowed/used tls-1.3 specific ciphers, see system.tlsv13_cipher_list setting, only used/required if $override_tls is true, default empty or system.tlsv13_cipher_list setting if $override_tls is true * optional list of allowed/used tls-1.3 specific ciphers, see system.tlsv13_cipher_list setting, only used/required if $override_tls is true, default empty or system.tlsv13_cipher_list setting if $override_tls is true
* @param string $description
* optional custom description (currently not used/shown in the frontend), default empty
* *
* @access admin * @access admin
* @throws \Exception * @throws \Exception
@@ -354,6 +356,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$tlsv13_cipher_list = $this->getParam('tlsv13_cipher_list', true, Settings::Get('system.tlsv13_cipher_list')); $tlsv13_cipher_list = $this->getParam('tlsv13_cipher_list', true, Settings::Get('system.tlsv13_cipher_list'));
} }
} }
$description = $this->getParam('description', true, '');
// validation // validation
$p_domain = strtolower($p_domain); $p_domain = strtolower($p_domain);
@@ -728,7 +731,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
'tlsv13_cipher_list' => $tlsv13_cipher_list, 'tlsv13_cipher_list' => $tlsv13_cipher_list,
'sslenabled' => $sslenabled, 'sslenabled' => $sslenabled,
'honorcipherorder' => $honorcipherorder, 'honorcipherorder' => $honorcipherorder,
'sessiontickets' => $sessiontickets 'sessiontickets' => $sessiontickets,
'description' => $description
); );
$ins_stmt = Database::prepare(" $ins_stmt = Database::prepare("
@@ -780,7 +784,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
`tlsv13_cipher_list` = :tlsv13_cipher_list, `tlsv13_cipher_list` = :tlsv13_cipher_list,
`ssl_enabled` = :sslenabled, `ssl_enabled` = :sslenabled,
`ssl_honorcipherorder` = :honorcipherorder, `ssl_honorcipherorder` = :honorcipherorder,
`ssl_sessiontickets`= :sessiontickets `ssl_sessiontickets` = :sessiontickets,
`description` = :description
"); ");
Database::pexecute($ins_stmt, $ins_data, true, true); Database::pexecute($ins_stmt, $ins_data, true, true);
$domainid = Database::lastInsertId(); $domainid = Database::lastInsertId();
@@ -932,6 +937,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
* optional whether to honor the (server) cipher order for this domain. default 0 (false), requires SSL * optional whether to honor the (server) cipher order for this domain. default 0 (false), requires SSL
* @param bool $sessiontickets * @param bool $sessiontickets
* optional whether to enable or disable TLS sessiontickets (RFC 5077) for this domain. default 1 (true), requires SSL * optional whether to enable or disable TLS sessiontickets (RFC 5077) for this domain. default 1 (true), requires SSL
* @param string $description
* optional custom description (currently not used/shown in the frontend), default empty
* *
* @access admin * @access admin
* @throws \Exception * @throws \Exception
@@ -1027,6 +1034,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$ssl_cipher_list = $result['ssl_cipher_list']; $ssl_cipher_list = $result['ssl_cipher_list'];
$tlsv13_cipher_list = $result['tlsv13_cipher_list']; $tlsv13_cipher_list = $result['tlsv13_cipher_list'];
} }
$description = $this->getParam('description', true, $result['description']);
// count subdomain usage of source-domain // count subdomain usage of source-domain
$subdomains_stmt = Database::prepare(" $subdomains_stmt = Database::prepare("
@@ -1589,6 +1597,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$update_data['sslenabled'] = $sslenabled; $update_data['sslenabled'] = $sslenabled;
$update_data['honorcipherorder'] = $honorcipherorder; $update_data['honorcipherorder'] = $honorcipherorder;
$update_data['sessiontickets'] = $sessiontickets; $update_data['sessiontickets'] = $sessiontickets;
$update_data['description'] = $description;
$update_data['id'] = $id; $update_data['id'] = $id;
$update_stmt = Database::prepare(" $update_stmt = Database::prepare("
@@ -1634,7 +1643,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
`tlsv13_cipher_list` = :tlsv13_cipher_list, `tlsv13_cipher_list` = :tlsv13_cipher_list,
`ssl_enabled` = :sslenabled, `ssl_enabled` = :sslenabled,
`ssl_honorcipherorder` = :honorcipherorder, `ssl_honorcipherorder` = :honorcipherorder,
`ssl_sessiontickets` = :sessiontickets `ssl_sessiontickets` = :sessiontickets,
`description` = :description
WHERE `id` = :id WHERE `id` = :id
"); ");
Database::pexecute($update_stmt, $update_data, true, true); Database::pexecute($update_stmt, $update_data, true, true);

View File

@@ -100,7 +100,7 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
// alternative email address to send info to // alternative email address to send info to
if (Settings::Get('panel.sendalternativemail') == 1) { if (Settings::Get('panel.sendalternativemail') == 1) {
$alternative_email = $idna_convert->encode(\Froxlor\Validate\Validate::validate($alternative_email, 'alternative_email', '', '', array(), true)); $alternative_email = $idna_convert->encode(\Froxlor\Validate\Validate::validate($alternative_email, 'alternative_email', '', '', array(), true));
if (!empty($alternative_email) && ! \Froxlor\Validate\Validate::validateEmail($alternative_email)) { if (! empty($alternative_email) && ! \Froxlor\Validate\Validate::validateEmail($alternative_email)) {
\Froxlor\UI\Response::standard_error('alternativeemailiswrong', $alternative_email, true); \Froxlor\UI\Response::standard_error('alternativeemailiswrong', $alternative_email, true);
} }
} else { } else {
@@ -192,7 +192,7 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
$replace_arr = array( $replace_arr = array(
'EMAIL' => $email_full, 'EMAIL' => $email_full,
'USERNAME' => $username, 'USERNAME' => $username,
'PASSWORD' => $password, 'PASSWORD' => htmlentities(htmlentities($password)),
'SALUTATION' => \Froxlor\User::getCorrectUserSalutation($customer), 'SALUTATION' => \Froxlor\User::getCorrectUserSalutation($customer),
'NAME' => $customer['name'], 'NAME' => $customer['name'],
'FIRSTNAME' => $customer['firstname'], 'FIRSTNAME' => $customer['firstname'],
@@ -236,7 +236,7 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
$this->mailer()->clearAddresses(); $this->mailer()->clearAddresses();
// customer wants to send the e-mail to an alternative email address too // customer wants to send the e-mail to an alternative email address too
if (Settings::Get('panel.sendalternativemail') == 1 && !empty($alternative_email)) { if (Settings::Get('panel.sendalternativemail') == 1 && ! empty($alternative_email)) {
// get template for mail subject // get template for mail subject
$mail_subject = $this->getMailTemplate($customer, 'mails', 'pop_success_alternative_subject', $replace_arr, $this->lng['mails']['pop_success_alternative']['subject']); $mail_subject = $this->getMailTemplate($customer, 'mails', 'pop_success_alternative_subject', $replace_arr, $this->lng['mails']['pop_success_alternative']['subject']);
// get template for mail body // get template for mail body
@@ -302,6 +302,8 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
* optional, update quota * optional, update quota
* @param string $email_password * @param string $email_password
* optional, update password * optional, update password
* @param bool $deactivated
* optional, admin-only
* *
* @access admin, customer * @access admin, customer
* @throws \Exception * @throws \Exception
@@ -331,6 +333,7 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
$password = $this->getParam('email_password', true, ''); $password = $this->getParam('email_password', true, '');
$quota = $this->getParam('email_quota', true, $result['quota']); $quota = $this->getParam('email_quota', true, $result['quota']);
$deactivated = $this->getBoolParam('deactivated', true, (strtolower($result['postfix']) == 'n' ? true : false));
// get needed customer info to reduce the email-account-counter by one // get needed customer info to reduce the email-account-counter by one
$customer = $this->getCustomerData(); $customer = $this->getCustomerData();
@@ -372,6 +375,18 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
$quota = 0; $quota = 0;
} }
if ($this->isAdmin()) {
if (($deactivated == true && strtolower($result['postfix']) == 'y') || ($deactivated == false && strtolower($result['postfix']) == 'n')) {
if (! empty($upd_query)) {
$upd_query .= ", ";
}
$upd_query .= "`postfix` = :postfix, `imap` = :imap, `pop3` = :pop3";
$upd_params['postfix'] = $deactivated ? 'N' : 'Y';
$upd_params['imap'] = $deactivated ? '0' : '1';
$upd_params['pop3'] = $deactivated ? '0' : '1';
}
}
// build update query // build update query
if (! empty($upd_query)) { if (! empty($upd_query)) {
$upd_stmt = Database::prepare(" $upd_stmt = Database::prepare("

View File

@@ -35,6 +35,8 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
* optional, required when called as admin (if $loginname is not specified) * optional, required when called as admin (if $loginname is not specified)
* @param string $loginname * @param string $loginname
* optional, required when called as admin (if $customerid is not specified) * optional, required when called as admin (if $customerid is not specified)
* @param string $description
* optional custom description (currently not used/shown in the frontend), default empty
* *
* @access admin, customer * @access admin, customer
* @throws \Exception * @throws \Exception
@@ -54,6 +56,7 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
// parameters // parameters
$iscatchall = $this->getBoolParam('iscatchall', true, 0); $iscatchall = $this->getBoolParam('iscatchall', true, 0);
$description = $this->getParam('description', true, '');
// validation // validation
if (substr($domain, 0, 4) != 'xn--') { if (substr($domain, 0, 4) != 'xn--') {
@@ -121,14 +124,16 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
`email` = :email, `email` = :email,
`email_full` = :email_full, `email_full` = :email_full,
`iscatchall` = :iscatchall, `iscatchall` = :iscatchall,
`domainid` = :domainid `domainid` = :domainid,
`description` = :description
"); ");
$params = array( $params = array(
"cid" => $customer['customerid'], "cid" => $customer['customerid'],
"email" => $email, "email" => $email,
"email_full" => $email_full, "email_full" => $email_full,
"iscatchall" => $iscatchall, "iscatchall" => $iscatchall,
"domainid" => $domain_check['id'] "domainid" => $domain_check['id'],
"description" => $description
); );
Database::pexecute($stmt, $params, true, true); Database::pexecute($stmt, $params, true, true);
@@ -167,7 +172,7 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$customer_ids = $this->getAllowedCustomerIds('email'); $customer_ids = $this->getAllowedCustomerIds('email');
$params['idea'] = ($id <= 0 ? $emailaddr : $id); $params['idea'] = ($id <= 0 ? $emailaddr : $id);
$result_stmt = Database::prepare("SELECT v.`id`, v.`email`, v.`email_full`, v.`iscatchall`, v.`destination`, v.`customerid`, v.`popaccountid`, v.`domainid`, u.`quota` $result_stmt = Database::prepare("SELECT v.`id`, v.`email`, v.`email_full`, v.`iscatchall`, v.`destination`, v.`customerid`, v.`popaccountid`, v.`domainid`, v.`description`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
FROM `" . TABLE_MAIL_VIRTUAL . "` v FROM `" . TABLE_MAIL_VIRTUAL . "` v
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id` LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ") WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
@@ -195,6 +200,8 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
* optional, required when called as admin (if $customerid is not specified) * optional, required when called as admin (if $customerid is not specified)
* @param boolean $iscatchall * @param boolean $iscatchall
* optional * optional
* @param string $description
* optional custom description (currently not used/shown in the frontend), default empty
* *
* @access admin, customer * @access admin, customer
* @throws \Exception * @throws \Exception
@@ -227,6 +234,7 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
// parameters // parameters
$iscatchall = $this->getBoolParam('iscatchall', true, $result['iscatchall']); $iscatchall = $this->getBoolParam('iscatchall', true, $result['iscatchall']);
$description = $this->getParam('description', true, $result['description']);
// get needed customer info to reduce the email-address-counter by one // get needed customer info to reduce the email-address-counter by one
$customer = $this->getCustomerData(); $customer = $this->getCustomerData();
@@ -256,12 +264,13 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$stmt = Database::prepare(" $stmt = Database::prepare("
UPDATE `" . TABLE_MAIL_VIRTUAL . "` UPDATE `" . TABLE_MAIL_VIRTUAL . "`
SET `email` = :email , `iscatchall` = :caflag SET `email` = :email , `iscatchall` = :caflag, `description` = :description
WHERE `customerid`= :cid AND `id`= :id WHERE `customerid`= :cid AND `id`= :id
"); ");
$params = array( $params = array(
"email" => $email, "email" => $email,
"caflag" => $iscatchall, "caflag" => $iscatchall,
"description" => $description,
"cid" => $customer['customerid'], "cid" => $customer['customerid'],
"id" => $id "id" => $id
); );
@@ -300,7 +309,7 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$result = array(); $result = array();
$query_fields = array(); $query_fields = array();
$result_stmt = Database::prepare(" $result_stmt = Database::prepare("
SELECT m.`id`, m.`domainid`, m.`email`, m.`email_full`, m.`iscatchall`, u.`quota`, m.`destination`, m.`popaccountid`, d.`domain`, u.`mboxsize` SELECT m.`id`, m.`domainid`, m.`email`, m.`email_full`, m.`iscatchall`, m.`destination`, m.`popaccountid`, d.`domain`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
FROM `" . TABLE_MAIL_VIRTUAL . "` m FROM `" . TABLE_MAIL_VIRTUAL . "` m
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`) LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`)
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`) LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`)

View File

@@ -245,7 +245,7 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
'COMPANY' => $customer['company'], 'COMPANY' => $customer['company'],
'CUSTOMER_NO' => $customer['customernumber'], 'CUSTOMER_NO' => $customer['customernumber'],
'USR_NAME' => $username, 'USR_NAME' => $username,
'USR_PASS' => $password, 'USR_PASS' => htmlentities(htmlentities($password)),
'USR_PATH' => \Froxlor\FileDir::makeCorrectDir(str_replace($customer['documentroot'], "/", $path)) 'USR_PATH' => \Froxlor\FileDir::makeCorrectDir(str_replace($customer['documentroot'], "/", $path))
); );
// get template for mail subject // get template for mail subject

View File

@@ -88,13 +88,13 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
// add database info to froxlor // add database info to froxlor
$stmt = Database::prepare(" $stmt = Database::prepare("
INSERT INTO `" . TABLE_PANEL_DATABASES . "` INSERT INTO `" . TABLE_PANEL_DATABASES . "`
SET SET
`customerid` = :customerid, `customerid` = :customerid,
`databasename` = :databasename, `databasename` = :databasename,
`description` = :description, `description` = :description,
`dbserver` = :dbserver `dbserver` = :dbserver
"); ");
$params = array( $params = array(
"customerid" => $customer['customerid'], "customerid" => $customer['customerid'],
"databasename" => $username, "databasename" => $username,
@@ -130,7 +130,7 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
'COMPANY' => $userinfo['company'], 'COMPANY' => $userinfo['company'],
'CUSTOMER_NO' => $userinfo['customernumber'], 'CUSTOMER_NO' => $userinfo['customernumber'],
'DB_NAME' => $username, 'DB_NAME' => $username,
'DB_PASS' => $password, 'DB_PASS' => htmlentities(htmlentities($password)),
'DB_DESC' => $databasedescription, 'DB_DESC' => $databasedescription,
'DB_SRV' => $sql_root['host'], 'DB_SRV' => $sql_root['host'],
'PMA_URI' => $pma 'PMA_URI' => $pma

View File

@@ -59,7 +59,7 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
); );
$query = "SELECT * FROM `" . TABLE_PANEL_DOMAINS . "` $query = "SELECT * FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `phpsettingid` = :id"; WHERE `phpsettingid` = :id AND `email_only` = '0' AND `phpenabled` = '1'";
if (! $with_subdomains) { if (! $with_subdomains) {
$query .= " AND `parentdomainid` = '0'"; $query .= " AND `parentdomainid` = '0'";

View File

@@ -565,7 +565,7 @@ class Apache extends HttpConfigBase
* *
* @return string * @return string
*/ */
protected function composePhpOptions($domain, $ssl_vhost = false) protected function composePhpOptions(&$domain, $ssl_vhost = false)
{ {
$php_options_text = ''; $php_options_text = '';
@@ -788,14 +788,6 @@ class Apache extends HttpConfigBase
)); ));
$logfiles_text .= ' CustomLog "|' . $command . '" ' . $logtype . "\n"; $logfiles_text .= ' CustomLog "|' . $command . '" ' . $logtype . "\n";
} else { } else {
// Create the logfile if it does not exist (fixes #46)
touch($error_log);
chown($error_log, Settings::Get('system.httpuser'));
chgrp($error_log, Settings::Get('system.httpgroup'));
touch($access_log);
chown($access_log, Settings::Get('system.httpuser'));
chgrp($access_log, Settings::Get('system.httpgroup'));
$logfiles_text .= ' ErrorLog "' . $error_log . '"' . "\n"; $logfiles_text .= ' ErrorLog "' . $error_log . '"' . "\n";
$logfiles_text .= ' CustomLog "' . $access_log . '" ' . $logtype . "\n"; $logfiles_text .= ' CustomLog "' . $access_log . '" ' . $logtype . "\n";
} }

View File

@@ -24,7 +24,7 @@ use Froxlor\Cron\Http\Php\PhpInterface;
class ApacheFcgi extends Apache class ApacheFcgi extends Apache
{ {
protected function composePhpOptions($domain, $ssl_vhost = false) protected function composePhpOptions(&$domain, $ssl_vhost = false)
{ {
$php_options_text = ''; $php_options_text = '';
@@ -43,6 +43,8 @@ class ApacheFcgi extends Apache
$php_options_text .= ' SuexecUserGroup "' . $domain['loginname'] . '" "' . $domain['loginname'] . '"' . "\n"; $php_options_text .= ' SuexecUserGroup "' . $domain['loginname'] . '" "' . $domain['loginname'] . '"' . "\n";
} }
$domain['fpm_socket'] = $php->getInterface()->getSocketFile();
// 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') {
$filesmatch = $phpconfig['fpm_settings']['limit_extensions']; $filesmatch = $phpconfig['fpm_settings']['limit_extensions'];
@@ -54,7 +56,7 @@ class ApacheFcgi extends Apache
// start block, cut off last pipe and close block // start block, cut off last pipe and close block
$filesmatch = '(' . str_replace(".", "\.", substr($filesmatch, 0, - 1)) . ')'; $filesmatch = '(' . str_replace(".", "\.", substr($filesmatch, 0, - 1)) . ')';
$php_options_text .= ' <FilesMatch \.' . $filesmatch . '$>' . "\n"; $php_options_text .= ' <FilesMatch \.' . $filesmatch . '$>' . "\n";
$php_options_text .= ' SetHandler proxy:unix:' . $php->getInterface()->getSocketFile() . '|fcgi://localhost' . "\n"; $php_options_text .= ' SetHandler proxy:unix:' . $domain['fpm_socket'] . '|fcgi://localhost' . "\n";
$php_options_text .= ' </FilesMatch>' . "\n"; $php_options_text .= ' </FilesMatch>' . "\n";
$mypath_dir = new \Froxlor\Http\Directory($domain['documentroot']); $mypath_dir = new \Froxlor\Http\Directory($domain['documentroot']);
@@ -80,7 +82,7 @@ class ApacheFcgi extends Apache
if ($phpconfig['pass_authorizationheader'] == '1') { if ($phpconfig['pass_authorizationheader'] == '1') {
$addheader = " -pass-header Authorization"; $addheader = " -pass-header Authorization";
} }
$php_options_text .= ' FastCgiExternalServer ' . $php->getInterface()->getAliasConfigDir() . $srvName . ' -socket ' . $php->getInterface()->getSocketFile() . ' -idle-timeout ' . $phpconfig['fpm_settings']['idle_timeout'] . $addheader . "\n"; $php_options_text .= ' FastCgiExternalServer ' . $php->getInterface()->getAliasConfigDir() . $srvName . ' -socket ' . $domain['fpm_socket'] . ' -idle-timeout ' . $phpconfig['fpm_settings']['idle_timeout'] . $addheader . "\n";
$php_options_text .= ' <Directory "' . \Froxlor\FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n"; $php_options_text .= ' <Directory "' . \Froxlor\FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
$filesmatch = $phpconfig['fpm_settings']['limit_extensions']; $filesmatch = $phpconfig['fpm_settings']['limit_extensions'];
$extensions = explode(" ", $filesmatch); $extensions = explode(" ", $filesmatch);

View File

@@ -98,8 +98,12 @@ class HttpConfigBase
'IP' => $ip, 'IP' => $ip,
'PORT' => $port, 'PORT' => $port,
'SCHEME' => ($is_ssl_vhost) ? 'https' : 'http', 'SCHEME' => ($is_ssl_vhost) ? 'https' : 'http',
'DOCROOT' => $domain['documentroot'] 'DOCROOT' => $domain['documentroot'],
'FPMSOCKET' => ''
); );
if ((int) Settings::Get('phpfpm.enabled') == 1 && isset($domain['fpm_socket']) && !empty($domain['fpm_socket'])) {
$templateVars['FPMSOCKET'] = $domain['fpm_socket'];
}
return \Froxlor\PhpHelper::replaceVariables($template, $templateVars); return \Froxlor\PhpHelper::replaceVariables($template, $templateVars);
} }

View File

@@ -497,8 +497,8 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron
private static function checkFsFilesAreNewer($domain, $cert_date = 0) private static function checkFsFilesAreNewer($domain, $cert_date = 0)
{ {
$certificate_folder = self::getWorkingDirFromEnv($domain); $certificate_folder = self::getWorkingDirFromEnv(strtolower($domain));
$ssl_file = \Froxlor\FileDir::makeCorrectFile($certificate_folder . '/' . $domain . '.cer'); $ssl_file = \Froxlor\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)) {
$cert_data = openssl_x509_parse(file_get_contents($ssl_file)); $cert_data = openssl_x509_parse(file_get_contents($ssl_file));

View File

@@ -364,7 +364,7 @@ class Lighttpd extends HttpConfigBase
return; return;
} }
protected function composePhpOptions($domain) protected function composePhpOptions(&$domain)
{ {
return; return;
} }

View File

@@ -22,7 +22,7 @@ use Froxlor\Cron\Http\Php\PhpInterface;
class LighttpdFcgi extends Lighttpd class LighttpdFcgi extends Lighttpd
{ {
protected function composePhpOptions($domain) protected function composePhpOptions(&$domain)
{ {
$php_options_text = ''; $php_options_text = '';
@@ -32,10 +32,11 @@ class LighttpdFcgi extends Lighttpd
// vhost data for php-fpm // vhost data for php-fpm
if ((int) Settings::Get('phpfpm.enabled') == 1) { if ((int) Settings::Get('phpfpm.enabled') == 1) {
$domain['fpm_socket'] = $php->getInterface()->getSocketFile();
$php_options_text = ' fastcgi.server = ( ' . "\n"; $php_options_text = ' fastcgi.server = ( ' . "\n";
$php_options_text .= "\t" . '".php" => (' . "\n"; $php_options_text .= "\t" . '".php" => (' . "\n";
$php_options_text .= "\t\t" . '"localhost" => (' . "\n"; $php_options_text .= "\t\t" . '"localhost" => (' . "\n";
$php_options_text .= "\t\t" . '"socket" => "' . $php->getInterface()->getSocketFile() . '",' . "\n"; $php_options_text .= "\t\t" . '"socket" => "' . $domain['fpm_socket'] . '",' . "\n";
$php_options_text .= "\t\t" . '"check-local" => "enable",' . "\n"; $php_options_text .= "\t\t" . '"check-local" => "enable",' . "\n";
$php_options_text .= "\t\t" . '"disable-time" => 1' . "\n"; $php_options_text .= "\t\t" . '"disable-time" => 1' . "\n";
$php_options_text .= "\t" . ')' . "\n"; $php_options_text .= "\t" . ')' . "\n";

View File

@@ -970,7 +970,7 @@ class Nginx extends HttpConfigBase
return $returnval; return $returnval;
} }
protected function composePhpOptions($domain, $ssl_vhost = false) protected function composePhpOptions(&$domain, $ssl_vhost = false)
{ {
$phpopts = ''; $phpopts = '';
if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') { if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') {

View File

@@ -22,7 +22,7 @@ use Froxlor\Cron\Http\Php\PhpInterface;
class NginxFcgi extends Nginx class NginxFcgi extends Nginx
{ {
protected function composePhpOptions($domain, $ssl_vhost = false) protected function composePhpOptions(&$domain, $ssl_vhost = false)
{ {
$php_options_text = ''; $php_options_text = '';
@@ -43,7 +43,8 @@ class NginxFcgi extends Nginx
if ($domain['ssl'] == '1' && $ssl_vhost) { if ($domain['ssl'] == '1' && $ssl_vhost) {
$php_options_text .= "\t\t" . 'fastcgi_param HTTPS on;' . "\n"; $php_options_text .= "\t\t" . 'fastcgi_param HTTPS on;' . "\n";
} }
$php_options_text .= "\t\t" . 'fastcgi_pass unix:' . $php->getInterface()->getSocketFile() . ";\n"; $domain['fpm_socket'] = $php->getInterface()->getSocketFile();
$php_options_text .= "\t\t" . 'fastcgi_pass unix:' . $domain['fpm_socket'] . ";\n";
$php_options_text .= "\t\t" . 'fastcgi_index index.php;' . "\n"; $php_options_text .= "\t\t" . 'fastcgi_index index.php;' . "\n";
$php_options_text .= "\t}\n\n"; $php_options_text .= "\t}\n\n";

View File

@@ -24,7 +24,7 @@ class Extrausers
{ {
// passwd // passwd
$passwd = '/var/lib/extrausers/passwd'; $passwd = '/var/lib/extrausers/passwd';
$sql = "SELECT customerid,username,'x' as password,uid,gid,'Froxlor User' as comment,homedir,shell, login_enabled FROM ftp_users ORDER BY uid ASC"; $sql = "SELECT customerid,username,'x' as password,uid,gid,'Froxlor User' as comment,homedir,shell, login_enabled FROM ftp_users ORDER BY uid, LENGTH(username) ASC";
self::generateFile($passwd, $sql, $cronlog); self::generateFile($passwd, $sql, $cronlog);
// group // group

View File

@@ -181,8 +181,8 @@ class Dns
// unset special spf required-entry // unset special spf required-entry
unset($required_entries[$entry['type']][md5("@SPF@")]); unset($required_entries[$entry['type']][md5("@SPF@")]);
} }
if (empty($primary_ns) && $entry['type'] == 'NS') { if (empty($primary_ns) && $entry['record'] == '@' && $entry['type'] == 'NS') {
// use the first NS entry as primary ns // use the first NS entry pertaining to the current domain as primary ns
$primary_ns = $entry['content']; $primary_ns = $entry['content'];
} }
// check for CNAME on @, www- or wildcard-Alias and remove A/AAAA record accordingly // check for CNAME on @, www- or wildcard-Alias and remove A/AAAA record accordingly
@@ -365,7 +365,11 @@ class Dns
} }
// PowerDNS does not like multi-line-format // PowerDNS does not like multi-line-format
$soa_content = $primary_ns . " " . self::escapeSoaAdminMail(Settings::Get('panel.adminmail')) . " "; $soa_email = Settings::Get('system.soaemail');
if ($soa_email == "") {
$soa_email = Settings::Get('panel.adminmail');
}
$soa_content = $primary_ns . " " . self::escapeSoaAdminMail($soa_email) . " ";
$soa_content .= $domain['bindserial'] . " "; $soa_content .= $domain['bindserial'] . " ";
// TODO for now, dummy time-periods // TODO for now, dummy time-periods
$soa_content .= "3600 900 604800 " . (int) Settings::Get('system.defaultttl'); $soa_content .= "3600 900 604800 " . (int) Settings::Get('system.defaultttl');

View File

@@ -7,10 +7,10 @@ final class Froxlor
{ {
// Main version variable // Main version variable
const VERSION = '0.10.24'; const VERSION = '0.10.26';
// Database version (YYYYMMDDC where C is a daily counter) // Database version (YYYYMMDDC where C is a daily counter)
const DBVERSION = '202101200'; const DBVERSION = '202103240';
// Distribution branding-tag (used for Debian etc.) // Distribution branding-tag (used for Debian etc.)
const BRANDING = ''; const BRANDING = '';

View File

@@ -168,7 +168,7 @@ class Crypt
$password = \Froxlor\Validate\Validate::validate($password, '/.*[0-9]+.*/', '/.*[0-9]+.*/', 'notrequiredpasswordcomplexity', array(), $json_response); $password = \Froxlor\Validate\Validate::validate($password, '/.*[0-9]+.*/', '/.*[0-9]+.*/', 'notrequiredpasswordcomplexity', array(), $json_response);
} }
if (Settings::Get('panel.password_special_char_required')) { if (Settings::Get('panel.password_special_char_required')) {
$password = \Froxlor\Validate\Validate::validate($password, '/.*[' . preg_quote(Settings::Get('panel.password_special_char')) . ']+.*/', '/.*[' . preg_quote(Settings::Get('panel.password_special_char')) . ']+.*/', 'notrequiredpasswordcomplexity', array(), $json_response); $password = \Froxlor\Validate\Validate::validate($password, '/.*[' . preg_quote(Settings::Get('panel.password_special_char'), '/') . ']+.*/', '/.*[' . preg_quote(Settings::Get('panel.password_special_char'), '/') . ']+.*/', 'notrequiredpasswordcomplexity', array(), $json_response);
} }
} }

View File

@@ -480,6 +480,18 @@ if (array_key_exists('css', $_themeoptions['variants'][$themevariant]) && is_arr
eval("\$header = \"" . \Froxlor\UI\Template::getTemplate('header', '1') . "\";"); eval("\$header = \"" . \Froxlor\UI\Template::getTemplate('header', '1') . "\";");
$current_year = date('Y', time()); $current_year = date('Y', time());
$panel_imprint_url = Settings::Get('panel.imprint_url');
if (!empty($panel_imprint_url) && strtolower(substr($panel_imprint_url, 0, 4)) != 'http') {
$panel_imprint_url = 'https://'.$panel_imprint_url;
}
$panel_terms_url = Settings::Get('panel.terms_url');
if (!empty($panel_terms_url) && strtolower(substr($panel_terms_url, 0, 4)) != 'http') {
$panel_terms_url = 'https://'.$panel_terms_url;
}
$panel_privacy_url = Settings::Get('panel.privacy_url');
if (!empty($panel_privacy_url) && strtolower(substr($panel_privacy_url, 0, 4)) != 'http') {
$panel_privacy_url = 'https://'.$panel_privacy_url;
}
eval("\$footer = \"" . \Froxlor\UI\Template::getTemplate('footer', '1') . "\";"); eval("\$footer = \"" . \Froxlor\UI\Template::getTemplate('footer', '1') . "\";");
unset($js); unset($js);

View File

@@ -683,7 +683,7 @@ $lng['message']['noreceipients'] = 'No e-mail has been sent because there are no
$lng['admin']['sslsettings'] = 'SSL settings'; $lng['admin']['sslsettings'] = 'SSL settings';
$lng['cronjobs']['notyetrun'] = 'Not yet run'; $lng['cronjobs']['notyetrun'] = 'Not yet run';
$lng['serversettings']['default_vhostconf']['title'] = 'Default vHost-settings'; $lng['serversettings']['default_vhostconf']['title'] = 'Default vHost-settings';
$lng['admin']['specialsettings_replacements'] = "You can use the following variables:<br/><code>{DOMAIN}</code>, <code>{DOCROOT}</code>, <code>{CUSTOMER}</code>, <code>{IP}</code>, <code>{PORT}</code>, <code>{SCHEME}</code><br/>"; $lng['admin']['specialsettings_replacements'] = "You can use the following variables:<br/><code>{DOMAIN}</code>, <code>{DOCROOT}</code>, <code>{CUSTOMER}</code>, <code>{IP}</code>, <code>{PORT}</code>, <code>{SCHEME}</code>, <code>{FPMSOCKET}</code> (if applicable)<br/>";
$lng['serversettings']['default_vhostconf']['description'] = 'The content of this field will be included into this ip/port vHost container directly. ' . $lng['admin']['specialsettings_replacements'] . ' Attention: The code won\'t be checked for any errors. If it contains errors, webserver might not start again!'; $lng['serversettings']['default_vhostconf']['description'] = 'The content of this field will be included into this ip/port vHost container directly. ' . $lng['admin']['specialsettings_replacements'] . ' Attention: The code won\'t be checked for any errors. If it contains errors, webserver might not start again!';
$lng['serversettings']['apache_globaldiropt']['title'] = 'Directory options for customer-prefix'; $lng['serversettings']['apache_globaldiropt']['title'] = 'Directory options for customer-prefix';
$lng['serversettings']['apache_globaldiropt']['description'] = 'The content of this field will be included into the 05_froxlor_dirfix_nofcgid.conf apache config. If empty, the default value is used:<br><br>apache >=2.4<br><code>Require all granted<br>AllowOverride All</code><br><br>apache <=2.2<br><code>Order allow,deny<br>allow from all</code>'; $lng['serversettings']['apache_globaldiropt']['description'] = 'The content of this field will be included into the 05_froxlor_dirfix_nofcgid.conf apache config. If empty, the default value is used:<br><br>apache >=2.4<br><code>Require all granted<br>AllowOverride All</code><br><br>apache <=2.2<br><code>Order allow,deny<br>allow from all</code>';
@@ -1908,6 +1908,7 @@ $lng['error']['dns_mx_needdom'] = 'The MX content value must be a valid domain-n
$lng['error']['dns_mx_noalias'] = 'The MX-content value cannot be an CNAME entry.'; $lng['error']['dns_mx_noalias'] = 'The MX-content value cannot be an CNAME entry.';
$lng['error']['dns_cname_invaliddom'] = 'Invalid domain-name for CNAME record'; $lng['error']['dns_cname_invaliddom'] = 'Invalid domain-name for CNAME record';
$lng['error']['dns_cname_nomorerr'] = 'There already exists a resource-record with the same record-name. It can not be used as CNAME.'; $lng['error']['dns_cname_nomorerr'] = 'There already exists a resource-record with the same record-name. It can not be used as CNAME.';
$lng['error']['dns_other_nomorerr'] = 'There already exists a CNAME record with the same record-name. It can not be used for another type.';
$lng['error']['dns_ns_invaliddom'] = 'Invalid domain-name for NS record'; $lng['error']['dns_ns_invaliddom'] = 'Invalid domain-name for NS record';
$lng['error']['dns_srv_prioempty'] = 'Invalid SRV priority given'; $lng['error']['dns_srv_prioempty'] = 'Invalid SRV priority given';
$lng['error']['dns_srv_invalidcontent'] = 'Invalid SRV content, must contain of fields weight, port and target, e.g.: 5 5060 sipserver.example.com.'; $lng['error']['dns_srv_invalidcontent'] = 'Invalid SRV content, must contain of fields weight, port and target, e.g.: 5 5060 sipserver.example.com.';
@@ -2104,3 +2105,14 @@ $lng['serversettings']['awstats']['logformat']['description'] = 'If you use cust
$lng['error']['cannotdeletesuperadmin'] = 'The first admin cannot be deleted.'; $lng['error']['cannotdeletesuperadmin'] = 'The first admin cannot be deleted.';
$lng['error']['no_wwwcnamae_ifwwwalias'] = 'Cannot set CNAME record for "www" as domain is set to generate a www-alias. Please change settings to either "No alias" or "Wildcard alias"'; $lng['error']['no_wwwcnamae_ifwwwalias'] = 'Cannot set CNAME record for "www" as domain is set to generate a www-alias. Please change settings to either "No alias" or "Wildcard alias"';
$lng['serversettings']['hide_incompatible_settings'] = 'Hide incompatible settings'; $lng['serversettings']['hide_incompatible_settings'] = 'Hide incompatible settings';
$lng['serversettings']['soaemail'] = 'Mail address to use in SOA records (defaults to sender address from panel settings if empty)';
$lng['imprint'] = 'Legal notes';
$lng['serversettings']['imprint_url']['title'] = 'URL to legal notes / imprint';
$lng['serversettings']['imprint_url']['description'] = 'Specify an URL to your legal notes / imprint site. The link will be visible on the login screen and on the footer when logged in.';
$lng['terms'] = 'Terms of use';
$lng['serversettings']['terms_url']['title'] = 'URL to terms of use';
$lng['serversettings']['terms_url']['description'] = 'Specify an URL to your terms of use site. The link will be visible on the login screen and on the footer when logged in.';
$lng['privacy'] = 'Privacy policy';
$lng['serversettings']['privacy_url']['title'] = 'URL to privacy policy';
$lng['serversettings']['privacy_url']['description'] = 'Specify an URL to your privacy policy site / imprint site. The link will be visible on the login screen and on the footer when logged in.';

View File

@@ -676,7 +676,7 @@ $lng['message']['noreceipients'] = 'Es wurde keine E-Mail versendet, da sich kei
$lng['admin']['sslsettings'] = 'SSL-Einstellungen'; $lng['admin']['sslsettings'] = 'SSL-Einstellungen';
$lng['cronjobs']['notyetrun'] = 'Bisher nicht gestartet'; $lng['cronjobs']['notyetrun'] = 'Bisher nicht gestartet';
$lng['serversettings']['default_vhostconf']['title'] = 'Standard vHost-Einstellungen'; $lng['serversettings']['default_vhostconf']['title'] = 'Standard vHost-Einstellungen';
$lng['admin']['specialsettings_replacements'] = "Die folgenden Variablen können verwendet werden:<br/><code>{DOMAIN}</code>, <code>{DOCROOT}</code>, <code>{CUSTOMER}</code>, <code>{IP}</code>, <code>{PORT}</code>, <code>{SCHEME}</code><br/>"; $lng['admin']['specialsettings_replacements'] = "Die folgenden Variablen können verwendet werden:<br/><code>{DOMAIN}</code>, <code>{DOCROOT}</code>, <code>{CUSTOMER}</code>, <code>{IP}</code>, <code>{PORT}</code>, <code>{SCHEME}</code>, <code>{FPMSOCKET}</code> (wenn zutreffend)<br/>";
$lng['serversettings']['default_vhostconf']['description'] = 'Der Inhalt dieses Feldes wird direkt in den IP/Port-vHost-Container übernommen. ' . $lng['admin']['specialsettings_replacements'] . '<br /><strong>ACHTUNG:</strong> Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Der Webserver könnte nicht mehr starten!'; $lng['serversettings']['default_vhostconf']['description'] = 'Der Inhalt dieses Feldes wird direkt in den IP/Port-vHost-Container übernommen. ' . $lng['admin']['specialsettings_replacements'] . '<br /><strong>ACHTUNG:</strong> Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Der Webserver könnte nicht mehr starten!';
$lng['serversettings']['default_vhostconf_domain']['description'] = 'Der Inhalt dieses Feldes wird direkt in jeden Domain-vHost-Container übernommen. ' . $lng['admin']['specialsettings_replacements'] . '<strong>ACHTUNG:</strong> Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Der Webserver könnte nicht mehr starten!'; $lng['serversettings']['default_vhostconf_domain']['description'] = 'Der Inhalt dieses Feldes wird direkt in jeden Domain-vHost-Container übernommen. ' . $lng['admin']['specialsettings_replacements'] . '<strong>ACHTUNG:</strong> Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Der Webserver könnte nicht mehr starten!';
$lng['serversettings']['apache_globaldiropt']['title'] = 'Kunden-Prefix Ordner-Optionen'; $lng['serversettings']['apache_globaldiropt']['title'] = 'Kunden-Prefix Ordner-Optionen';
@@ -1558,6 +1558,7 @@ $lng['error']['dns_mx_needdom'] = 'Der Wert des MX Eintrags muss ein gültiger D
$lng['error']['dns_mx_noalias'] = 'Der MX Eintrag darf kein CNAME Eintrag sein.'; $lng['error']['dns_mx_noalias'] = 'Der MX Eintrag darf kein CNAME Eintrag sein.';
$lng['error']['dns_cname_invaliddom'] = 'Ungültiger Domain-Name für CNAME Eintrag'; $lng['error']['dns_cname_invaliddom'] = 'Ungültiger Domain-Name für CNAME Eintrag';
$lng['error']['dns_cname_nomorerr'] = 'Es existiert bereits ein Eintrag mit dem gleichen Namen. Dieser Eintrag kann daher nicht für CNAME genutzt werden.'; $lng['error']['dns_cname_nomorerr'] = 'Es existiert bereits ein Eintrag mit dem gleichen Namen. Dieser Eintrag kann daher nicht für CNAME genutzt werden.';
$lng['error']['dns_other_nomorerr'] = 'Es existiert bereits ein CNAME Eintrag mit dem gleichen Namen. Dieser Eintrag kann daher nicht für einen anderen genutzt werden.';
$lng['error']['dns_ns_invaliddom'] = 'Ungültiger Domain-Name für NS Eintrag'; $lng['error']['dns_ns_invaliddom'] = 'Ungültiger Domain-Name für NS Eintrag';
$lng['error']['dns_srv_prioempty'] = 'Ungültige SRV Priorität angegeben'; $lng['error']['dns_srv_prioempty'] = 'Ungültige SRV Priorität angegeben';
$lng['error']['dns_srv_invalidcontent'] = 'Ungültiger Wert des SRV Eintrags, dieser muss aus den Feldern weight, port und target, bestehen. Bsp.: 5 5060 sipserver.example.com.'; $lng['error']['dns_srv_invalidcontent'] = 'Ungültiger Wert des SRV Eintrags, dieser muss aus den Feldern weight, port und target, bestehen. Bsp.: 5 5060 sipserver.example.com.';
@@ -1750,3 +1751,14 @@ $lng['serversettings']['awstats']['logformat']['description'] = 'Wenn ein benutz
$lng['error']['cannotdeletesuperadmin'] = 'Der erste Administrator kann nicht gelöscht werden.'; $lng['error']['cannotdeletesuperadmin'] = 'Der erste Administrator kann nicht gelöscht werden.';
$lng['error']['no_wwwcnamae_ifwwwalias'] = 'Es kann kein CNAME Eintrag für "www" angelegt werden, da die Domain einen www-Alias aktiviert hat. Ändere diese Einstellung auf "Kein Alias" oder "Wildcard Alias"'; $lng['error']['no_wwwcnamae_ifwwwalias'] = 'Es kann kein CNAME Eintrag für "www" angelegt werden, da die Domain einen www-Alias aktiviert hat. Ändere diese Einstellung auf "Kein Alias" oder "Wildcard Alias"';
$lng['serversettings']['hide_incompatible_settings'] = 'Inkompatible Einstellungen ausblenden'; $lng['serversettings']['hide_incompatible_settings'] = 'Inkompatible Einstellungen ausblenden';
$lng['serversettings']['soaemail'] = 'Mail-Adresse für SOA-Einträge (verwendet Panel-Absender-Name der Panel-Einstellungen falls leer)';
$lng['imprint'] = 'Impressum';
$lng['serversettings']['imprint_url']['title'] = 'URL zum Impressum';
$lng['serversettings']['imprint_url']['description'] = 'Die URL zur Impressums-Seite. Der Link ist auf der Login-Seite und wenn eingeloggt, in der Fußzeile sichtbar.';
$lng['terms'] = 'AGB';
$lng['serversettings']['terms_url']['title'] = 'URL zu den AGB';
$lng['serversettings']['terms_url']['description'] = 'Die URL zur AGB-Seite. Der Link ist auf der Login-Seite und wenn eingeloggt, in der Fußzeile sichtbar.';
$lng['privacy'] = 'Datenschutzerklärung';
$lng['serversettings']['privacy_url']['title'] = 'URL zur Datenschutzerklärung';
$lng['serversettings']['privacy_url']['description'] = 'Die URL zur Datenschutzerklärungs-Seite. Der Link ist auf der Login-Seite und wenn eingeloggt, in der Fußzeile sichtbar.';

View File

@@ -34,7 +34,7 @@
<if $row['letsencrypt'] == '1'> <if $row['letsencrypt'] == '1'>
&nbsp;<img src="templates/{$theme}/assets/img/icons/ssl_letsencrypt.png" alt="{$lng['panel']['letsencrypt']}" title="{$lng['panel']['letsencrypt']}" /> &nbsp;<img src="templates/{$theme}/assets/img/icons/ssl_letsencrypt.png" alt="{$lng['panel']['letsencrypt']}" title="{$lng['panel']['letsencrypt']}" />
</if> </if>
<if !(isset($row['domainaliasid']) && $row['domainaliasid'] != 0) && $row['id'] != \Froxlor\Settings::Get('system.hostname_id')> <if !(isset($row['domainaliasid']) && !empty($row['domainaliasid'])) && $row['id'] != \Froxlor\Settings::Get('system.hostname_id')>
<if !(isset($row['standardsubdomain']) && $row['standardsubdomain'] == $row['id'])> <if !(isset($row['standardsubdomain']) && $row['standardsubdomain'] == $row['id'])>
&nbsp;<a href="{$linker->getLink(array('section' => 'domains', 'page' => $page, 'action' => 'delete', 'id' => $row['id']))}"> &nbsp;<a href="{$linker->getLink(array('section' => 'domains', 'page' => $page, 'action' => 'delete', 'id' => $row['id']))}">
<img src="templates/{$theme}/assets/img/icons/delete.png" alt="{$lng['panel']['delete']}" title="{$lng['panel']['delete']}" /> <img src="templates/{$theme}/assets/img/icons/delete.png" alt="{$lng['panel']['delete']}" title="{$lng['panel']['delete']}" />

View File

@@ -1737,4 +1737,11 @@ td.size-50 {
font-weight: 700; font-weight: 700;
padding: 5px 10px; padding: 5px 10px;
color: #ffe !important; color: #ffe !important;
} }
.footer-link:after {
content: " |";
}
.footer-link:last-child:after {
content: "";
}

View File

@@ -15,7 +15,7 @@
</td> </td>
<td> <td>
<if $row['aliasdomain'] == ''>{$row['documentroot']}</if> <if $row['aliasdomain'] == ''>{$row['documentroot']}</if>
<if isset($row['aliasdomainid']) && $row['aliasdomainid'] != 0>{$lng['domains']['aliasdomain']} {$row['aliasdomain']}</if> <if isset($row['aliasdomainid']) && !empty($row['aliasdomainid'])>{$lng['domains']['aliasdomain']} {$row['aliasdomain']}</if>
</td> </td>
<td> <td>
<if $row['caneditdomain'] == '1'> <if $row['caneditdomain'] == '1'>
@@ -28,7 +28,7 @@
<img src="templates/{$theme}/assets/img/icons/view.png" alt="{$lng['panel']['viewlogs']}" title="{$lng['panel']['viewlogs']}" /> <img src="templates/{$theme}/assets/img/icons/view.png" alt="{$lng['panel']['viewlogs']}" title="{$lng['panel']['viewlogs']}" />
</a> </a>
</if> </if>
<if $row['parentdomainid'] != '0' && !(isset($row['domainaliasid']) && $row['domainaliasid'] != 0)> <if $row['parentdomainid'] != '0' && (!isset($row['domainaliasid']) || empty($row['domainaliasid']))>
<a href="{$linker->getLink(array('section' => 'domains', 'page' => 'domains', 'action' => 'delete', 'id' => $row['id']))}"> <a href="{$linker->getLink(array('section' => 'domains', 'page' => 'domains', 'action' => 'delete', 'id' => $row['id']))}">
<img src="templates/{$theme}/assets/img/icons/delete.png" alt="{$lng['panel']['delete']}" title="{$lng['panel']['delete']}" /> <img src="templates/{$theme}/assets/img/icons/delete.png" alt="{$lng['panel']['delete']}" title="{$lng['panel']['delete']}" />
</a>&nbsp; </a>&nbsp;
@@ -46,10 +46,10 @@
<if $row['letsencrypt'] == '1'> <if $row['letsencrypt'] == '1'>
<img src="templates/{$theme}/assets/img/icons/ssl_letsencrypt.png" alt="{$lng['panel']['letsencrypt']}" title="{$lng['panel']['letsencrypt']}" /> <img src="templates/{$theme}/assets/img/icons/ssl_letsencrypt.png" alt="{$lng['panel']['letsencrypt']}" title="{$lng['panel']['letsencrypt']}" />
</if> </if>
<if $row['parentdomainid'] == '0' && !(isset($row['domainaliasid']) && $row['domainaliasid'] != 0)> <if $row['parentdomainid'] == '0' && (!isset($row['domainaliasid']) || empty($row['domainaliasid']))>
({$lng['domains']['isassigneddomain']})&nbsp; ({$lng['domains']['isassigneddomain']})&nbsp;
</if> </if>
<if isset($row['domainaliasid']) && $row['domainaliasid'] != 0> <if isset($row['domainaliasid']) && !empty($row['domainaliasid'])>
<a href="{$linker->getLink(array('section' => 'domains', 'page' => 'domains', 'searchfield' => 'd.aliasdomain', 'searchtext' => $row['id']))}">{$lng['domains']['hasaliasdomains']}</a> <a href="{$linker->getLink(array('section' => 'domains', 'page' => 'domains', 'searchfield' => 'd.aliasdomain', 'searchtext' => $row['id']))}">{$lng['domains']['hasaliasdomains']}</a>
</if> </if>
</td> </td>

View File

@@ -4,11 +4,14 @@
</div> </div>
</if> </if>
<footer> <footer>
<span><img src="templates/{$theme}/assets/img/logo_grey.png" alt="Froxlor" /> <span><img src="templates/{$theme}/assets/img/logo_grey.png" alt="Froxlor" />
<if (\Froxlor\Settings::Get('admin.show_version_login') == '1' && $filename == 'index.php') || ($filename != 'index.php' && \Froxlor\Settings::Get('admin.show_version_footer') == '1')> <if (\Froxlor\Settings::Get('admin.show_version_login') == '1' && $filename == 'index.php') || ($filename != 'index.php' && \Froxlor\Settings::Get('admin.show_version_footer') == '1')>
{$version}{$branding} {$version}{$branding}
</if> </if>
&copy; 2009-{$current_year} by <a href="http://www.froxlor.org/" rel="external">the Froxlor Team</a><br /> &copy; 2009-{$current_year} by <a href="http://www.froxlor.org/" rel="external">the Froxlor Team</a><br />
<if (\Froxlor\Settings::Get('panel.imprint_url')) != ''><a href="{$panel_imprint_url}" target="_blank" class="footer-link">{$lng['imprint']}</a></if>
<if (\Froxlor\Settings::Get('panel.terms_url')) != ''><a href="{$panel_terms_url}" target="_blank" class="footer-link">{$lng['terms']}</a></if>
<if (\Froxlor\Settings::Get('panel.privacy_url')) != ''><a href="{$panel_privacy_url}" target="_blank" class="footer-link">{$lng['privacy']}</a></if>
</span> </span>
<if $lng['translator'] != ''> <if $lng['translator'] != ''>
<br /><span>{$lng['panel']['translator']}: {$lng['translator']} <br /><span>{$lng['panel']['translator']}: {$lng['translator']}

View File

@@ -115,6 +115,14 @@ class CustomersTest extends TestCase
$json_result = Customers::getLocal($admin_userdata)->listing(); $json_result = Customers::getLocal($admin_userdata)->listing();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
$this->assertEquals(1, $result['count']); $this->assertEquals(1, $result['count']);
$this->assertFalse(isset($result['list'][0]['webspace_used']));
$json_result = Customers::getLocal($admin_userdata, [
'show_usages' => true
])->listing();
$result = json_decode($json_result, true)['data'];
$this->assertEquals(1, $result['count']);
$this->assertTrue(isset($result['list'][0]['webspace_used']));
$json_result = Customers::getLocal($admin_userdata)->listingCount(); $json_result = Customers::getLocal($admin_userdata)->listingCount();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];

View File

@@ -101,6 +101,7 @@ class DomainZonesTest extends TestCase
} }
/** /**
*
* @depends testCustomerDomainZonesAddA * @depends testCustomerDomainZonesAddA
*/ */
public function testAdminDomainZonesListing() public function testAdminDomainZonesListing()
@@ -303,14 +304,14 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
$this->assertTrue(count($result) > 1); $this->assertTrue(count($result) > 1);
$found = false; $found = false;
foreach ($result as $entry) { foreach ($result as $entry) {
if (substr($entry, -strlen($content)) == $content) { if (substr($entry, - strlen($content)) == $content) {
$found = true; $found = true;
break; break;
} }
@@ -328,7 +329,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -341,7 +342,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIssueWithTwoParameters() public function testAdminDomainZonesAddCAAIssueWithTwoParameters()
@@ -353,7 +354,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -366,7 +367,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAInvalidIssueValue() public function testAdminDomainZonesAddCAAInvalidIssueValue()
@@ -378,7 +379,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -393,7 +394,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -408,7 +409,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -423,7 +424,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -436,7 +437,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIssueWildWithParameters() public function testAdminDomainZonesAddCAAIssueWildWithParameters()
@@ -448,7 +449,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -461,7 +462,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIssueWildWithTwoParameters() public function testAdminDomainZonesAddCAAIssueWildWithTwoParameters()
@@ -473,7 +474,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -486,7 +487,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAInvalidIssueWildValue() public function testAdminDomainZonesAddCAAInvalidIssueWildValue()
@@ -498,7 +499,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -513,7 +514,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -528,7 +529,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -543,7 +544,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -556,7 +557,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIodefMailInvalid() public function testAdminDomainZonesAddCAAIodefMailInvalid()
@@ -568,7 +569,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -583,7 +584,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -596,7 +597,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIodefHttpInvalid() public function testAdminDomainZonesAddCAAIodefHttpInvalid()
@@ -608,7 +609,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -623,7 +624,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -636,7 +637,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIodefHttpsInvalid() public function testAdminDomainZonesAddCAAIodefHttpsInvalid()
@@ -648,7 +649,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -745,6 +746,38 @@ class DomainZonesTest extends TestCase
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
} }
/**
*
* @depends testAdminDomainZonesAddCname
*/
public function testAdminDomainZonesAddForExistingCname()
{
global $admin_userdata;
// set domain to www-alias
$data = [
'domainname' => 'test2.local',
'selectserveralias' => '1'
];
Domains::getLocal($admin_userdata, $data)->update();
foreach ([
'A' => '127.0.0.1',
'AAAA' => '::1',
'MX' => 'mail.example.com.',
'NS' => 'ns.example.com.'
] as $type => $val) {
$data = [
'domainname' => 'test2.local',
'record' => 'db',
'type' => $type,
'content' => $val
];
$this->expectExceptionMessage('There already exists a CNAME record with the same record-name. It can not be used for another type.');
DomainZones::getLocal($admin_userdata, $data)->add();
}
}
/** /**
* *
* @depends testAdminDomainZonesAddCname * @depends testAdminDomainZonesAddCname

View File

@@ -32,13 +32,15 @@ class DomainsTest extends TestCase
'ssl_protocols' => array( 'ssl_protocols' => array(
'TLSv1.2', 'TLSv1.2',
'TLSv1.3' 'TLSv1.3'
) ),
'description' => 'awesome domain'
]; ];
$json_result = Domains::getLocal($admin_userdata, $data)->add(); $json_result = Domains::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
$this->assertEquals($customer_userdata['documentroot'] . 'test.local/', $result['documentroot']); $this->assertEquals($customer_userdata['documentroot'] . 'test.local/', $result['documentroot']);
$this->assertTrue(in_array('TLSv1.3', explode(",", $result['ssl_protocols']))); $this->assertTrue(in_array('TLSv1.3', explode(",", $result['ssl_protocols'])));
$this->assertEquals('0', $result['isemaildomain']); $this->assertEquals('0', $result['isemaildomain']);
$this->assertEquals('awesome domain', $result['description']);
} }
/** /**
@@ -207,7 +209,8 @@ class DomainsTest extends TestCase
'domainname' => 'test.local', 'domainname' => 'test.local',
'email_only' => 1, 'email_only' => 1,
'override_tls' => 0, 'override_tls' => 0,
'documentroot' => 'web' 'documentroot' => 'web',
'description' => 'changed desc'
]; ];
$json_result = Domains::getLocal($admin_userdata, $data)->update(); $json_result = Domains::getLocal($admin_userdata, $data)->update();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -215,6 +218,7 @@ class DomainsTest extends TestCase
$this->assertFalse(in_array('TLSv1.3', explode(",", $result['ssl_protocols']))); $this->assertFalse(in_array('TLSv1.3', explode(",", $result['ssl_protocols'])));
$this->assertEquals('test.local', $result['domain']); $this->assertEquals('test.local', $result['domain']);
$this->assertEquals($customer_userdata['documentroot'] . 'web/', $result['documentroot']); $this->assertEquals($customer_userdata['documentroot'] . 'web/', $result['documentroot']);
$this->assertEquals('changed desc', $result['description']);
} }
/** /**

View File

@@ -36,12 +36,14 @@ class MailsTest extends TestCase
$data = [ $data = [
'email_part' => 'info', 'email_part' => 'info',
'domain' => 'test2.local' 'domain' => 'test2.local',
'description' => 'awesome email'
]; ];
$json_result = Emails::getLocal($customer_userdata, $data)->add(); $json_result = Emails::getLocal($customer_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
$this->assertEquals("info@test2.local", $result['email_full']); $this->assertEquals("info@test2.local", $result['email_full']);
$this->assertEquals(0, $result['iscatchall']); $this->assertEquals(0, $result['iscatchall']);
$this->assertEquals('awesome email', $result['description']);
// reset setting // reset setting
Settings::Set('panel.customer_hide_options', '', true); Settings::Set('panel.customer_hide_options', '', true);
@@ -87,11 +89,13 @@ class MailsTest extends TestCase
$data = [ $data = [
'emailaddr' => 'catchall@test2.local', 'emailaddr' => 'catchall@test2.local',
'iscatchall' => 1 'iscatchall' => 1,
'description' => 'now with catchall'
]; ];
$json_result = Emails::getLocal($customer_userdata, $data)->update(); $json_result = Emails::getLocal($customer_userdata, $data)->update();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
$this->assertEquals(1, $result['iscatchall']); $this->assertEquals(1, $result['iscatchall']);
$this->assertEquals('now with catchall', $result['description']);
} }
public function testCustomerEmailForwardersAdd() public function testCustomerEmailForwardersAdd()
@@ -444,6 +448,36 @@ class MailsTest extends TestCase
$this->assertEquals(0, $result['quota']); $this->assertEquals(0, $result['quota']);
} }
public function testAdminEmailAccountsUpdateDeactivated()
{
global $admin_userdata;
// disable
$data = [
'emailaddr' => 'info@test2.local',
'loginname' => 'test1',
'deactivated' => 1
];
$json_result = EmailAccounts::getLocal($admin_userdata, $data)->update();
$result = json_decode($json_result, true)['data'];
// quota is disabled
$this->assertEquals(0, $result['imap']);
$this->assertEquals(0, $result['pop3']);
$this->assertEquals('N', $result['postfix']);
// re-enable
$data = [
'emailaddr' => 'info@test2.local',
'loginname' => 'test1',
'deactivated' => 0
];
$json_result = EmailAccounts::getLocal($admin_userdata, $data)->update();
$result = json_decode($json_result, true)['data'];
// quota is disabled
$this->assertEquals(1, $result['imap']);
$this->assertEquals(1, $result['pop3']);
$this->assertEquals('Y', $result['postfix']);
}
public function testAdminEmailAccountsUndefinedGet() public function testAdminEmailAccountsUndefinedGet()
{ {
global $admin_userdata; global $admin_userdata;