Merge remote-tracking branch 'origin/2.1.x' into feature-backup

This commit is contained in:
Maurice Preuß (envoyr)
2023-06-06 14:41:41 +02:00
86 changed files with 818 additions and 448 deletions

View File

@@ -272,7 +272,8 @@ abstract class ApiCommand extends ApiParameter
$ops = [
'<',
'>',
'='
'=',
'<>'
];
$first = true;
foreach ($search as $field => $valoper) {

View File

@@ -95,7 +95,7 @@ class Admins extends ApiCommand implements ResourceEntity
public function listing()
{
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list admins");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list admins");
$query_fields = [];
$result_stmt = Database::prepare("
SELECT *
@@ -407,7 +407,7 @@ class Admins extends ApiCommand implements ResourceEntity
];
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get admin '" . $result['loginname'] . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get admin '" . $result['loginname'] . "'");
return $this->response($result);
}
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
@@ -705,7 +705,7 @@ class Admins extends ApiCommand implements ResourceEntity
WHERE `adminid` = :adminid
");
Database::pexecute($upd_stmt, $upd_data, true, true);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] edited admin '" . $result['loginname'] . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] edited admin '" . $result['loginname'] . "'");
// get all admin-data for return-array
$result = $this->apiCall('Admins.get', [

View File

@@ -97,7 +97,7 @@ class Certificates extends ApiCommand implements ResourceEntity
}
if (!$has_cert) {
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, true);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ssl-certificate for '" . $domain['domain'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ssl-certificate for '" . $domain['domain'] . "'");
$result = $this->apiCall('Certificates.get', [
'id' => $domain['id']
]);
@@ -248,7 +248,7 @@ class Certificates extends ApiCommand implements ResourceEntity
$ssl_ca_file = $this->getParam('ssl_ca_file', true, '');
$ssl_cert_chainfile = $this->getParam('ssl_cert_chainfile', true, '');
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, false);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ssl-certificate for '" . $domain['domain'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ssl-certificate for '" . $domain['domain'] . "'");
$result = $this->apiCall('Certificates.get', [
'id' => $domain['id']
]);
@@ -470,7 +470,7 @@ class Certificates extends ApiCommand implements ResourceEntity
if ($chk['letsencrypt'] == '1') {
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $chk['domain']);
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] removed ssl-certificate for '" . $chk['domain'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] removed ssl-certificate for '" . $chk['domain'] . "'");
return $this->response($result);
}
throw new Exception("Unable to determine SSL certificate. Maybe no access?", 406);

View File

@@ -147,7 +147,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity
// insert task to re-generate the cron.d-file
Cronjob::inserttask(TaskId::REBUILD_CRON);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
$result = $this->apiCall('Cronjobs.get', [
'id' => $id
]);
@@ -177,7 +177,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity
public function listing()
{
if ($this->isAdmin()) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list cronjobs");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list cronjobs");
$query_fields = [];
$result_stmt = Database::prepare("
SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());

View File

@@ -212,7 +212,7 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
$result[] = $entry;
}
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list customer-backups");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list customer-backups");
return $this->response([
'count' => count($result),
'list' => $result

View File

@@ -895,7 +895,7 @@ class Customers extends ApiCommand implements ResourceEntity
$result['dbspace_used'] = 0;
}
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get customer '" . $result['loginname'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get customer '" . $result['loginname'] . "'");
return $this->response($result);
}
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
@@ -1327,7 +1327,7 @@ class Customers extends ApiCommand implements ResourceEntity
'vu' => $valid_until
], true, true);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'");
Cronjob::inserttask(TaskId::REBUILD_VHOST);
}
@@ -1538,7 +1538,7 @@ class Customers extends ApiCommand implements ResourceEntity
Database::query($admin_update_query);
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited user '" . $result['loginname'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited user '" . $result['loginname'] . "'");
/*
* move customer to another admin/reseller; #1166
@@ -1911,7 +1911,7 @@ class Customers extends ApiCommand implements ResourceEntity
// now, recalculate the resource-usage for the old and the new admin
User::updateCounters(false);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] moved user '" . $c_result['loginname'] . "' from admin/reseller '" . $c_result['adminname'] . " to admin/reseller '" . $a_result['loginname'] . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] moved user '" . $c_result['loginname'] . "' from admin/reseller '" . $c_result['adminname'] . " to admin/reseller '" . $a_result['loginname'] . "'");
$result = $this->apiCall('Customers.get', [
'id' => $c_result['customerid']

View File

@@ -144,7 +144,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
];
Database::pexecute($stmt, $params, true, true);
$id = Database::lastInsertId();
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-option for '" . $userpath . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added directory-option for '" . $userpath . "'");
Cronjob::inserttask(TaskId::REBUILD_VHOST);
$result = $this->apiCall('DirOptions.get', [
@@ -247,7 +247,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
$params['id'] = $id;
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory options for '" . $result['path'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get directory options for '" . $result['path'] . "'");
return $this->response($result);
}
$key = "id #" . $id;
@@ -331,7 +331,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
"id" => $id
];
Database::pexecute($stmt, $params, true, true);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited directory options for '" . str_replace($customer['documentroot'], '/', $result['path']) . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited directory options for '" . str_replace($customer['documentroot'], '/', $result['path']) . "'");
}
$result = $this->apiCall('DirOptions.get', [
@@ -379,7 +379,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-options");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list directory-options");
return $this->response([
'count' => count($result),
'list' => $result
@@ -478,7 +478,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
"customerid" => $customer_data['customerid'],
"id" => $id
], true, true);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'");
Cronjob::inserttask(TaskId::REBUILD_VHOST);
return $this->response($result);
}

View File

@@ -129,7 +129,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
];
Database::pexecute($stmt, $params, true, true);
$id = Database::lastInsertId();
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-protection for '" . $username . " (" . $path . ")'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added directory-protection for '" . $username . " (" . $path . ")'");
Cronjob::inserttask(TaskId::REBUILD_VHOST);
$result = $this->apiCall('DirProtections.get', [
@@ -196,7 +196,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
$params['idun'] = ($id <= 0 ? $username : $id);
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory protection for '" . $result['path'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get directory protection for '" . $result['path'] . "'");
return $this->response($result);
}
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
@@ -279,7 +279,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
Cronjob::inserttask(TaskId::REBUILD_VHOST);
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'");
$result = $this->apiCall('DirProtections.get', [
'id' => $result['id']
]);
@@ -325,7 +325,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-protections");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list directory-protections");
return $this->response([
'count' => count($result),
'list' => $result
@@ -413,7 +413,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
"id" => $id
]);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'");
Cronjob::inserttask(TaskId::REBUILD_VHOST);
return $this->response($result);
}

View File

@@ -413,7 +413,7 @@ class DomainZones extends ApiCommand implements ResourceEntity
$zone = Dns::createDomainZone($id);
$zonefile = (string)$zone;
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get dns-zone for '" . $result['domain'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get dns-zone for '" . $result['domain'] . "'");
return $this->response(explode("\n", $zonefile));
}

View File

@@ -76,7 +76,7 @@ class Domains extends ApiCommand implements ResourceEntity
$query_fields = [];
$result_stmt = Database::prepare("
SELECT
`d`.*, `c`.`loginname`, `c`.`deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`, `c`.`adminid` as customeradmin,
`d`.*, `c`.`loginname`, `c`.`deactivated` as `customer_deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`, `c`.`adminid` as customeradmin,
`ad`.`id` AS `aliasdomainid`, `ad`.`domain` AS `aliasdomain`
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
@@ -110,7 +110,7 @@ class Domains extends ApiCommand implements ResourceEntity
*
* @param number $domain_id
* @param bool $ssl_only
* optional, return only ssl enabled ip's, default false
* optional, return only ssl enabled ips, default false
* @return array
*/
private function getIpsForDomain($domain_id = 0, $ssl_only = false)
@@ -190,9 +190,6 @@ class Domains extends ApiCommand implements ResourceEntity
* optional, whether to create an exclusive web-logfile for this domain, default 0 (false)
* @param int $alias
* optional, domain-id of a domain that the new domain should be an alias of, default 0 (none)
* @param int $issubof
* optional, domain-id of a domain this domain is a subdomain of (required for webserver-cronjob to
* generate the correct order), default 0 (none)
* @param string $registration_date
* optional, date of domain registration in form of YYYY-MM-DD, default empty (none)
* @param string $termination_date
@@ -210,7 +207,7 @@ class Domains extends ApiCommand implements ResourceEntity
* @param string $ssl_specialsettings
* optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty
* @param bool $include_specialsettings
* optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false
* optional, whether to include non-ssl specialsettings in the generated ssl-vhost, default false
* @param bool $notryfiles
* optional, [nginx only] do not generate the default try-files directive, default 0 (false)
* @param bool $writeaccesslog
@@ -219,7 +216,7 @@ class Domains extends ApiCommand implements ResourceEntity
* optional, Enable writing an error-log file for this domain, default 1 (true)
* @param string $documentroot
* optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be
* aware, if path starts with / it it considered a full path, not relative to customer-docroot. Also
* aware, if path starts with / it is considered a full path, not relative to customer-docroot. Also
* specifying a URL is possible here (redirect), default empty (autogenerated)
* @param bool $phpenabled
* optional, whether php is enabled for this domain, default 0 (false)
@@ -244,7 +241,7 @@ class Domains extends ApiCommand implements ResourceEntity
* optional, do NOT set the systems default ssl ip addresses if none are given via $ssl_ipandport
* parameter
* @param bool $sslenabled
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
* optional, whether SSL is enabled for this domain, regardless of the assigned ssl-ips, default
* 1 (true)
* @param bool $http2
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
@@ -252,9 +249,9 @@ class Domains extends ApiCommand implements ResourceEntity
* @param int $hsts_maxage
* optional max-age value for HSTS header
* @param bool $hsts_sub
* optional whether or not to add subdomains to the HSTS header
* optional whether to add subdomains to the HSTS header
* @param bool $hsts_preload
* optional whether or not to preload HSTS header value
* optional whether to preload HSTS header value
* @param bool $ocsp_stapling
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
* @param bool $honorcipherorder
@@ -263,7 +260,7 @@ class Domains extends ApiCommand implements ResourceEntity
* optional whether to enable or disable TLS sessiontickets (RFC 5077) for this domain. default 1
* (true), requires SSL
* @param bool $override_tls
* optional whether or not to override system-tls settings like protocol, ssl-ciphers and if applicable
* optional whether to override system-tls settings like protocol, ssl-ciphers and if applicable
* tls-1.3 ciphers, requires change_serversettings flag for the admin, default false
* @param array $ssl_protocols
* optional list of allowed/used ssl/tls protocols, see system.ssl_protocols setting, only used/required
@@ -298,7 +295,6 @@ class Domains extends ApiCommand implements ResourceEntity
$serveraliasoption = $this->getParam('selectserveralias', true, Settings::Get('system.domaindefaultalias'));
$speciallogfile = $this->getBoolParam('speciallogfile', true, 0);
$aliasdomain = intval($this->getParam('alias', true, 0));
$issubof = $this->getParam('issubof', true, 0);
$registration_date = $this->getParam('registration_date', true, '');
$termination_date = $this->getParam('termination_date', true, '');
$caneditdomain = $this->getBoolParam('caneditdomain', true, 0);
@@ -665,10 +661,6 @@ class Domains extends ApiCommand implements ResourceEntity
$serveraliasoption = '0';
}
if ($issubof <= 0) {
$issubof = '0';
}
$idna_convert = new IdnaWrapper();
if ($domain == '') {
Response::standardError([
@@ -723,7 +715,6 @@ class Domains extends ApiCommand implements ResourceEntity
'phpsettingid' => $phpsettingid,
'mod_fcgid_starter' => $mod_fcgid_starter,
'mod_fcgid_maxrequests' => $mod_fcgid_maxrequests,
'ismainbutsubto' => $issubof,
'letsencrypt' => $letsencrypt,
'http2' => $http2,
'hsts' => $hsts_maxage,
@@ -777,7 +768,6 @@ class Domains extends ApiCommand implements ResourceEntity
`phpsettingid` = :phpsettingid,
`mod_fcgid_starter` = :mod_fcgid_starter,
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
`ismainbutsubto` = :ismainbutsubto,
`letsencrypt` = :letsencrypt,
`http2` = :http2,
`hsts` = :hsts,
@@ -898,7 +888,7 @@ class Domains extends ApiCommand implements ResourceEntity
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
}
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get domain '" . $result['domain'] . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get domain '" . $result['domain'] . "'");
return $this->response($result);
}
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
@@ -1069,9 +1059,6 @@ class Domains extends ApiCommand implements ResourceEntity
* default 0 (false)
* @param int $alias
* optional, domain-id of a domain that the new domain should be an alias of, default 0 (none)
* @param int $issubof
* optional, domain-id of a domain this domain is a subdomain of (required for webserver-cronjob to
* generate the correct order), default 0 (none)
* @param string $registration_date
* optional, date of domain registration in form of YYYY-MM-DD, default empty (none)
* @param string $termination_date
@@ -1089,7 +1076,7 @@ class Domains extends ApiCommand implements ResourceEntity
* @param string $ssl_specialsettings
* optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty
* @param bool $include_specialsettings
* optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false
* optional, whether to include non-ssl specialsettings in the generated ssl-vhost, default false
* @param bool $specialsettingsforsubdomains
* optional, whether to apply specialsettings to all subdomains of this domain, default is read from
* setting system.apply_specialsettings_default
@@ -1101,7 +1088,7 @@ class Domains extends ApiCommand implements ResourceEntity
* optional, Enable writing an error-log file for this domain, default 1 (true)
* @param string $documentroot
* optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be
* aware, if path starts with / it it considered a full path, not relative to customer-docroot. Also
* aware, if path starts with / it is considered a full path, not relative to customer-docroot. Also
* specifying a URL is possible here (redirect), default empty (autogenerated)
* @param bool $phpenabled
* optional, whether php is enabled for this domain, default 0 (false)
@@ -1130,7 +1117,7 @@ class Domains extends ApiCommand implements ResourceEntity
* optional, if set to true and no $ssl_ipandport value is given, the ip's get removed, otherwise, the
* currently set value is used, default false
* @param bool $sslenabled
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
* optional, whether SSL is enabled for this domain, regardless of the assigned ssl-ips, default
* 1 (true)
* @param bool $http2
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
@@ -1138,9 +1125,9 @@ class Domains extends ApiCommand implements ResourceEntity
* @param int $hsts_maxage
* optional max-age value for HSTS header
* @param bool $hsts_sub
* optional whether or not to add subdomains to the HSTS header
* optional whether to add subdomains to the HSTS header
* @param bool $hsts_preload
* optional whether or not to preload HSTS header value
* optional whether to preload HSTS header value
* @param bool $ocsp_stapling
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
* @param bool $honorcipherorder
@@ -1150,6 +1137,8 @@ class Domains extends ApiCommand implements ResourceEntity
* (true), requires SSL
* @param string $description
* optional custom description (currently not used/shown in the frontend), default empty
* @param bool $deactivated
* optional, if 1 (true) the domain can be deactivated/suspended
*
* @access admin
* @return string json-encoded array
@@ -1191,7 +1180,6 @@ class Domains extends ApiCommand implements ResourceEntity
$speciallogfile = $this->getBoolParam('speciallogfile', true, $result['speciallogfile']);
$speciallogverified = $this->getBoolParam('speciallogverified', true, 0);
$aliasdomain = intval($this->getParam('alias', true, $result['aliasdomain']));
$issubof = $this->getParam('issubof', true, $result['ismainbutsubto']);
$registration_date = $this->getParam('registration_date', true, $result['registration_date']);
$termination_date = $this->getParam('termination_date', true, $result['termination_date']);
$caneditdomain = $this->getBoolParam('caneditdomain', true, $result['caneditdomain']);
@@ -1246,6 +1234,7 @@ class Domains extends ApiCommand implements ResourceEntity
$tlsv13_cipher_list = $result['tlsv13_cipher_list'];
}
$description = $this->getParam('description', true, $result['description']);
$deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']);
// count subdomain usage of source-domain
$subdomains_stmt = Database::prepare("
@@ -1640,10 +1629,6 @@ class Domains extends ApiCommand implements ResourceEntity
Response::standardError('domainisaliasorothercustomer', '', true);
}
if ($issubof <= 0) {
$issubof = '0';
}
if ($serveraliasoption != '1' && $serveraliasoption != '2') {
$serveraliasoption = '0';
}
@@ -1666,7 +1651,6 @@ class Domains extends ApiCommand implements ResourceEntity
|| $writeaccesslog != $result['writeaccesslog']
|| $writeerrorlog != $result['writeerrorlog']
|| $aliasdomain != $result['aliasdomain']
|| $issubof != $result['ismainbutsubto']
|| $email_only != $result['email_only']
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|| $letsencrypt != $result['letsencrypt']
@@ -1801,7 +1785,7 @@ class Domains extends ApiCommand implements ResourceEntity
Database::pexecute($upd_stmt, [
'id' => $id
], true, true);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] removed specialsettings on all subdomains of domain #" . $id);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] removed specialsettings on all subdomains of domain #" . $id);
}
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
@@ -1837,7 +1821,6 @@ class Domains extends ApiCommand implements ResourceEntity
$update_data['writeerrorlog'] = $writeerrorlog;
$update_data['registration_date'] = $registration_date;
$update_data['termination_date'] = $termination_date;
$update_data['ismainbutsubto'] = $issubof;
$update_data['letsencrypt'] = $letsencrypt;
$update_data['http2'] = $http2;
$update_data['hsts'] = $hsts_maxage;
@@ -1852,6 +1835,7 @@ class Domains extends ApiCommand implements ResourceEntity
$update_data['honorcipherorder'] = $honorcipherorder;
$update_data['sessiontickets'] = $sessiontickets;
$update_data['description'] = $description;
$update_data['deactivated'] = $deactivated;
$update_data['id'] = $id;
$update_stmt = Database::prepare("
@@ -1885,7 +1869,6 @@ class Domains extends ApiCommand implements ResourceEntity
`writeerrorlog` = :writeerrorlog,
`registration_date` = :registration_date,
`termination_date` = :termination_date,
`ismainbutsubto` = :ismainbutsubto,
`letsencrypt` = :letsencrypt,
`http2` = :http2,
`hsts` = :hsts,
@@ -1899,11 +1882,36 @@ class Domains extends ApiCommand implements ResourceEntity
`ssl_enabled` = :sslenabled,
`ssl_honorcipherorder` = :honorcipherorder,
`ssl_sessiontickets` = :sessiontickets,
`description` = :description
`description` = :description,
`deactivated` = :deactivated
WHERE `id` = :id
");
Database::pexecute($update_stmt, $update_data, true, true);
// activate/deactivate domain-based services
if ($deactivated != $result['deactivated']) {
// deactivate email accounts
$yesno = ($deactivated ? 'N' : 'Y');
$pop3 = ($deactivated ? '0' : (int)$customer['pop3']);
$imap = ($deactivated ? '0' : (int)$customer['imap']);
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_MAIL_USERS . "`
SET `postfix`= :yesno, `pop3` = :pop3, `imap` = :imap
WHERE `customerid` = :customerid AND `domainid` = :domainid
");
Database::pexecute($upd_stmt, [
'yesno' => $yesno,
'pop3' => $pop3,
'imap' => $imap,
'customerid' => $customerid,
'domainid' => $id
]);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " domain '" . $result['domain'] . "'");
Cronjob::inserttask(TaskId::REBUILD_VHOST);
}
$_update_data['customerid'] = $customerid;
$_update_data['adminid'] = $adminid;
$_update_data['phpenabled'] = $phpenabled;
@@ -1921,6 +1929,7 @@ class Domains extends ApiCommand implements ResourceEntity
$_update_data['honorcipherorder'] = $honorcipherorder;
$_update_data['sessiontickets'] = $sessiontickets;
$_update_data['parentdomainid'] = $id;
$_update_data['deactivated'] = $deactivated;
// if php config is to be set for all subdomains, check here
$update_phpconfig = '';
@@ -1953,7 +1962,8 @@ class Domains extends ApiCommand implements ResourceEntity
`ssl_cipher_list` = :ssl_cipher_list,
`tlsv13_cipher_list` = :tlsv13_cipher_list,
`ssl_honorcipherorder` = :honorcipherorder,
`ssl_sessiontickets` = :sessiontickets
`ssl_sessiontickets` = :sessiontickets,
`deactivated` = :deactivated
" . $update_phpconfig . $upd_specialsettings . $updatechildren . $update_sslredirect . "
WHERE `parentdomainid` = :parentdomainid
");
@@ -2073,9 +2083,6 @@ class Domains extends ApiCommand implements ResourceEntity
* optional, the domain-id
* @param string $domainname
* optional, the domainname
* @param bool $delete_mainsubdomains
* optional, remove also domains that are subdomains of this domain but added as main domains; default
* false
* @param bool $is_stdsubdomain
* optional, default false, specify whether it's a std-subdomain you are deleting as it does not count
* as subdomain-resource
@@ -2091,7 +2098,6 @@ class Domains extends ApiCommand implements ResourceEntity
$dn_optional = $id > 0;
$domainname = $this->getParam('domainname', $dn_optional, '');
$is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0);
$remove_subbutmain_domains = $this->getParam('delete_mainsubdomains', true, 0);
$result = $this->apiCall('Domains.get', [
'id' => $id,
@@ -2099,15 +2105,10 @@ class Domains extends ApiCommand implements ResourceEntity
]);
$id = $result['id'];
// check for deletion of main-domains which are logically subdomains, #329
$rsd_sql = '';
if ($remove_subbutmain_domains) {
$rsd_sql .= " OR `ismainbutsubto` = :id";
}
$subresult_stmt = Database::prepare("
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE (`id` = :id OR `parentdomainid` = :id " . $rsd_sql . ")");
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE (`id` = :id OR `parentdomainid` = :id)
");
Database::pexecute($subresult_stmt, [
'id' => $id
], true, true);
@@ -2129,23 +2130,10 @@ class Domains extends ApiCommand implements ResourceEntity
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] deleted domain/s from mail-tables");
}
// if mainbutsubto-domains are not to be deleted, re-assign the (ismainbutsubto value of the main
// domain which is being deleted) as their new ismainbutsubto value
if ($remove_subbutmain_domains !== 1) {
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
`ismainbutsubto` = :newIsMainButSubtoValue
WHERE `ismainbutsubto` = :deletedMainDomainId
");
Database::pexecute($upd_stmt, [
'newIsMainButSubtoValue' => $result['ismainbutsubto'],
'deletedMainDomainId' => $id
], true, true);
}
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `id` = :id OR `parentdomainid` = :id " . $rsd_sql);
DELETE FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `id` = :id OR `parentdomainid` = :id
");
Database::pexecute($del_stmt, [
'id' => $id
], true, true);
@@ -2221,7 +2209,7 @@ class Domains extends ApiCommand implements ResourceEntity
// remove domain from acme.sh / lets encrypt if used
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $result['domain']);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] deleted domain/subdomains (#" . $result['id'] . ")");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted domain/subdomains (#" . $result['id'] . ")");
User::updateCounters();
Cronjob::inserttask(TaskId::REBUILD_VHOST);
// Using nameserver, insert a task which rebuilds the server config
@@ -2230,4 +2218,114 @@ class Domains extends ApiCommand implements ResourceEntity
}
throw new Exception("Not allowed to execute given command.", 403);
}
/**
* duplicate domain entry by either id or domainname. All parameters from Domains.add() can be used
* to overwrite source entity values if necessary.
*
* @param int $id
* optional, the domain-id
* @param string $domainname
* optional, the domainname
* @param string $domain
* required, name of the new domain to be added
*
* @access admin
* @return string json-encoded array
* @throws Exception
*/
public function duplicate()
{
if ($this->isAdmin()) {
// parameters
$id = $this->getParam('id', true, 0);
$dn_optional = $id > 0;
$domainname = $this->getParam('domainname', $dn_optional, '');
$p_domain = $this->getParam('domain');
// get requested domain
$result = $this->apiCall('Domains.get', [
'id' => $id,
'domainname' => $domainname,
]);
// clear some defaults
unset($result['domain_ace']);
unset($result['adminid']);
unset($result['documentroot']);
unset($result['registration_date']);
unset($result['termination_date']);
unset($result['zonefile']);
// clear auto-generated values
unset($result['bindserial']);
unset($result['dkim_privkey']);
unset($result['dkim_pubkey']);
// clear api-call generated fields
unset($result['domain_hascert']);
// set correct ip/port information
$domain_ips = $result['ipsandports'];
unset($result['ipsandports']);
$result['ipandport'] = [];
$result['ssl_ipandport'] = [];
foreach ($domain_ips as $dip) {
if ($dip['ssl'] == 1) {
$result['ssl_ipandport'][] = $dip['id'];
} else {
$result['ipandport'][] = $dip['id'];
}
}
// check whether we are changing the customer/owner
if ($this->getParam('customerid', true, 0) == 0 && $this->getParam('loginname', true, '') == '') {
$customerid = $result['customerid'];
} else {
$customer = $this->getCustomerData();
$customerid = $customer['customerid'];
}
// check for alias-domain and whether it belongs to the target user
if (!empty($result['aliasdomain']) && $customerid == $result['customerid']) {
// duplicate alias entry
$result['alias'] = $result['aliasdomain'];
}
unset($result['aliasdomain']);
// validate possible fpm configs and whether the customer is allowed to use them
if ($customerid != $result['customerid']) {
$allowed_phpconfigs = json_decode($customer['allowed_phpconfigs'] ?? '[]', true);
if (empty($allowed_phpconfigs)) {
// system defaults
unset($result['phpsettingid']);
} elseif (!in_array($result['phpsettingid'], $allowed_phpconfigs)) {
// use the first customer allowed config
$result['phpsettingid'] = array_shift($allowed_phpconfigs);
}
}
// translate serveralias values
$result['selectserveralias'] = 2;
if ((int)$result['wwwserveralias'] == 1) {
$result['selectserveralias'] = 1;
} elseif ((int)$result['iswildcarddomain'] == 1) {
$result['selectserveralias'] = 0;
}
unset($result['wwwserveralias']);
unset($result['iswildcarddomain']);
$additional_params = $this->getParamList();
// unset unneeded params from this call
unset($additional_params['id']);
unset($additional_params['domainname']);
unset($additional_params['domain']);
// set new values and merge with optional add() parameters
$new_domain = array_merge($result, $additional_params);
$new_domain['domain'] = $p_domain;
$result_new = $this->apiCall('Domains.add', $new_domain);
return $this->response($result_new);
}
throw new Exception("Not allowed to execute given command.", 403);
}
}

View File

@@ -95,9 +95,18 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
$customer = $this->getCustomerData('email_accounts');
// check for imap||pop3 == 1, see #1298
// d00p, 6.5.2023 @revert this - if a customer has resources which allow email accounts
// it implicitly allowed SMTP, e.g. sending of emails which also requires an account to exist
/*
if ($customer['imap'] != '1' && $customer['pop3'] != '1') {
Response::standardError('notallowedtouseaccounts', '', true);
}
*/
if (!empty($emailaddr)) {
$idna_convert = new IdnaWrapper();
$emailaddr = $idna_convert->encode($emailaddr);
}
// get email address
$result = $this->apiCall('Emails.get', [
@@ -306,7 +315,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
}
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email account for '" . $result['email_full'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email account for '" . $result['email_full'] . "'");
$result = $this->apiCall('Emails.get', [
'emailaddr' => $result['email_full']
]);
@@ -357,6 +366,11 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
$ea_optional = $id > 0;
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
if (!empty($emailaddr)) {
$idna_convert = new IdnaWrapper();
$emailaddr = $idna_convert->encode($emailaddr);
}
// validation
$result = $this->apiCall('Emails.get', [
'id' => $id,
@@ -450,7 +464,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
Admins::increaseUsage($customer['adminid'], 'email_quota_used', '', ($quota - $result['quota']));
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated email account '" . $result['email_full'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated email account '" . $result['email_full'] . "'");
$result = $this->apiCall('Emails.get', [
'emailaddr' => $result['email_full']
]);
@@ -556,7 +570,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
Customers::decreaseUsage($customer['customerid'], 'email_accounts_used');
Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $quota);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email account for '" . $result['email_full'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted email account for '" . $result['email_full'] . "'");
return $this->response($result);
}
}

View File

@@ -89,7 +89,7 @@ class EmailDomains extends ApiCommand implements ResourceEntity
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE,
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO,
"[API] list email-domains");
return $this->response([
'count' => count($result),

View File

@@ -77,6 +77,11 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
$idna_convert = new IdnaWrapper();
$destination = $idna_convert->encode($destination);
if (!empty($emailaddr)) {
$idna_convert = new IdnaWrapper();
$emailaddr = $idna_convert->encode($emailaddr);
}
$result = $this->apiCall('Emails.get', [
'id' => $id,
'emailaddr' => $emailaddr
@@ -116,7 +121,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
// update customer usage
Customers::increaseUsage($customer['customerid'], 'email_forwarders_used');
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email forwarder for '" . $result['email_full'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email forwarder for '" . $result['email_full'] . "'");
$result = $this->apiCall('Emails.get', [
'emailaddr' => $result['email_full']
@@ -293,7 +298,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
// update customer usage
Customers::decreaseUsage($customer['customerid'], 'email_forwarders_used');
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email forwarder for '" . $result['email_full'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted email forwarder for '" . $result['email_full'] . "'");
$result = $this->apiCall('Emails.get', [
'emailaddr' => $result['email_full']

View File

@@ -88,9 +88,12 @@ class Emails extends ApiCommand implements ResourceEntity
$domain_check = $this->apiCall('SubDomains.get', [
'domainname' => $domain
], true);
if ($domain_check['isemaildomain'] == 0) {
if ((int)$domain_check['isemaildomain'] == 0) {
Response::standardError('maindomainnonexist', $domain, true);
}
if ((int)$domain_check['deactivated'] == 1) {
Response::standardError('maindomaindeactivated', $domain, true);
}
if (Settings::Get('catchall.catchall_enabled') != '1') {
$iscatchall = 0;
@@ -159,7 +162,7 @@ class Emails extends ApiCommand implements ResourceEntity
// update customer usage
Customers::increaseUsage($customer['customerid'], 'emails_used');
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email address '" . $email_full . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email address '" . $email_full . "'");
$result = $this->apiCall('Emails.get', [
'emailaddr' => $email_full
@@ -199,7 +202,7 @@ class Emails extends ApiCommand implements ResourceEntity
);
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get email address '" . $result['email_full'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get email address '" . $result['email_full'] . "'");
return $this->response($result);
}
$key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'");
@@ -294,7 +297,7 @@ class Emails extends ApiCommand implements ResourceEntity
"id" => $id
];
Database::pexecute($stmt, $params, true, true);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'");
$result = $this->apiCall('Emails.get', [
'emailaddr' => $result['email_full']
@@ -340,7 +343,7 @@ class Emails extends ApiCommand implements ResourceEntity
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list email-addresses");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list email-addresses");
return $this->response([
'count' => count($result),
'list' => $result
@@ -445,7 +448,7 @@ class Emails extends ApiCommand implements ResourceEntity
], true, true);
Customers::decreaseUsage($customer['customerid'], 'emails_used');
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email address '" . $result['email_full'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted email address '" . $result['email_full'] . "'");
return $this->response($result);
}
}

View File

@@ -64,7 +64,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
public function listing()
{
if ($this->isAdmin()) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list fpm-daemons");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list fpm-daemons");
$query_fields = [];
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "`" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
@@ -258,7 +258,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
$id = Database::lastInsertId();
Cronjob::inserttask(TaskId::REBUILD_VHOST);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
$result = $this->apiCall('FpmDaemons.get', [
'id' => $id
]);
@@ -384,7 +384,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
Database::pexecute($upd_stmt, $upd_data, true, true);
Cronjob::inserttask(TaskId::REBUILD_VHOST);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
$result = $this->apiCall('FpmDaemons.get', [
'id' => $id
]);
@@ -433,7 +433,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
], true, true);
Cronjob::inserttask(TaskId::REBUILD_VHOST);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
return $this->response($result);
}
throw new Exception("Not allowed to execute given command.", 403);

View File

@@ -37,6 +37,7 @@ use Froxlor\Settings;
use Froxlor\SImExporter;
use Froxlor\System\Cronjob;
use Froxlor\System\Crypt;
use Froxlor\Validate\Validate;
use PDO;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
@@ -72,7 +73,7 @@ class Froxlor extends ApiCommand
if (empty($uc_data) || empty($response) || $uc_data['ts'] + self::UPDATE_CHECK_INTERVAL < time() || $uc_data['channel'] != Settings::Get('system.update_channel') || $force_ucheck) {
// log our actions
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] checking for updates");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] checking for updates");
// check for new version
$aucheck = AutoUpdate::checkVersion();
@@ -142,7 +143,7 @@ class Froxlor extends ApiCommand
{
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
$json_str = $this->getParam('json_str');
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "User " . $this->getUserDetail('loginname') . " imported settings");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "User " . $this->getUserDetail('loginname') . " imported settings");
try {
SImExporter::import($json_str);
Cronjob::inserttask(TaskId::REBUILD_VHOST);
@@ -269,6 +270,79 @@ class Froxlor extends ApiCommand
return $this->response(Crypt::generatePassword($length));
}
/**
* return a one-time login link URL for a given user
*
* @param int $customerid optional, required if $loginname is not specified, user to create link for
* @param string $loginname optional, required if $customerid is not specified, user to create link for
* @param int $valid_time optional, value in seconds how long the link will be valid, default is 10 seconds, valid values are numbers from 10 to 120
* @param string $allowed_from optional, comma separated list of ip addresses or networks to allow login from via this link
*
* @access admin
* @return string json-encoded array [base => domain, uri => relative link]
* @throws Exception
*/
public function generateLoginLink()
{
if ($this->isAdmin()) {
$customer = $this->getCustomerData();
// cannot create link for deactivated users
if ((int)$customer['deactivated'] == 1) {
throw new Exception("Cannot generate link for deactivated user", 406);
}
$valid_time = (int)$this->getParam('valid_time', true, 10);
$allowed_from = $this->getParam('allowed_from', true, '');
$valid_time = Validate::validate($valid_time, 'valid time', '/^(1[0-1][0-9]|120|[1-9][0-9])$/', 'invalid_validtime', [10], true);
// validate allowed_from
if (!empty($allowed_from)) {
$ip_list = array_map('trim', explode(",", $allowed_from));
$_check_list = $ip_list;
foreach ($_check_list as $idx => $ip) {
if (Validate::validate_ip2($ip, true, 'invalidip', true, true, true) == false) {
throw new Exception('Invalid ip address', 406);
}
// check for cidr
if (strpos($ip, '/') !== false) {
$ipparts = explode("/", $ip);
// shorten IP
$ip = inet_ntop(inet_pton($ipparts[0]));
// re-add cidr
$ip .= '/' . $ipparts[1];
} else {
// shorten IP
$ip = inet_ntop(inet_pton($ip));
}
$ip_list[$idx] = $ip;
}
$allowed_from = implode(",", array_unique($ip_list));
}
$hash = hash('sha256', openssl_random_pseudo_bytes(64 * 64));
$ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_PANEL_LOGINLINKS . "`
SET `hash` = :hash, `loginname` = :loginname, `valid_until` = :validuntil, `allowed_from` = :allowedfrom
ON DUPLICATE KEY UPDATE `hash` = :hash, `valid_until` = :validuntil, `allowed_from` = :allowedfrom
");
Database::pexecute($ins_stmt, [
'hash' => $hash,
'loginname' => $customer['loginname'],
'validuntil' => time() + $valid_time,
'allowedfrom' => $allowed_from
]);
return $this->response([
'base' => 'https://' . Settings::Get('system.hostname') . '/' . (Settings::Get('system.froxlordirectlyviahostname') != 1 ? basename(\Froxlor\Froxlor::getInstallDir()) . '/' : ''),
'uri' => 'index.php?action=ll&ln=' . $customer['loginname'] . '&h=' . $hash
]);
}
throw new Exception("Not allowed to execute given command.", 403);
}
/**
* can be used to remotely run the integritiy checks froxlor implements
*

View File

@@ -257,7 +257,7 @@ class Ftps extends ApiCommand implements ResourceEntity
Customers::increaseUsage($customer['customerid'], 'ftp_lastaccountnumber');
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ftp-account '" . $username . " (" . $path . ")'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ftp-account '" . $username . " (" . $path . ")'");
Cronjob::inserttask(TaskId::CREATE_FTP);
if ($sendinfomail == 1) {
@@ -302,7 +302,7 @@ class Ftps extends ApiCommand implements ResourceEntity
$this->mailer()->clearAddresses();
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] added ftp-user '" . $username . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ftp-user '" . $username . "'");
$result = $this->apiCall('Ftps.get', [
'username' => $username
@@ -367,7 +367,7 @@ class Ftps extends ApiCommand implements ResourceEntity
$params['idun'] = ($id <= 0 ? $username : $id);
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get ftp-user '" . $result['username'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get ftp-user '" . $result['username'] . "'");
return $this->response($result);
}
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
@@ -453,7 +453,7 @@ class Ftps extends ApiCommand implements ResourceEntity
"id" => $id,
"password" => $cryptPassword
], true, true);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ftp-account password for '" . $result['username'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-account password for '" . $result['username'] . "'");
}
// path update?
@@ -471,7 +471,7 @@ class Ftps extends ApiCommand implements ResourceEntity
"customerid" => $customer['customerid'],
"id" => $id
], true, true);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ftp-account homdir for '" . $result['username'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-account homdir for '" . $result['username'] . "'");
}
}
// it's the task for "new ftp" but that will
@@ -533,7 +533,7 @@ class Ftps extends ApiCommand implements ResourceEntity
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list ftp-users");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list ftp-users");
return $this->response([
'count' => count($result),
'list' => $result

View File

@@ -61,7 +61,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
public function listing()
{
if ($this->isAdmin()) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list hosting-plans");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list hosting-plans");
$query_fields = [];
$result_stmt = Database::prepare("
SELECT p.*, a.loginname as adminname
@@ -227,7 +227,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
'valuearr' => json_encode($value_arr)
];
Database::pexecute($ins_stmt, $ins_data, true, true);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added hosting-plan '" . $name . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] added hosting-plan '" . $name . "'");
$result = $this->apiCall('HostingPlans.get', [
'planname' => $name
]);
@@ -264,7 +264,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
}
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get hosting-plan '" . $result['name'] . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get hosting-plan '" . $result['name'] . "'");
return $this->response($result);
}
$key = ($id > 0 ? "id #" . $id : "planname '" . $planname . "'");
@@ -414,7 +414,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
'id' => $id
];
Database::pexecute($upd_stmt, $update_data, true, true);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] updated hosting-plan '" . $result['name'] . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] updated hosting-plan '" . $result['name'] . "'");
return $this->response($update_data);
}
throw new Exception("Not allowed to execute given command.", 403);

View File

@@ -65,7 +65,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
public function listing()
{
if ($this->isAdmin() && ($this->getUserDetail('change_serversettings') || !empty($this->getUserDetail('ip')))) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list ips and ports");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list ips and ports");
$ip_where = "";
$append_where = false;
if (!empty($this->getUserDetail('ip')) && $this->getUserDetail('ip') != -1) {
@@ -335,7 +335,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
'id' => $id
], true, true);
if ($result) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get ip " . $result['ip'] . " " . $result['port']);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get ip " . $result['ip'] . " " . $result['port']);
return $this->response($result);
}
throw new Exception("IP/port with id #" . $id . " could not be found", 404);

View File

@@ -26,14 +26,15 @@
namespace Froxlor\Api\Commands;
use Exception;
use PDO;
use PDOException;
use Froxlor\Froxlor;
use Froxlor\PhpHelper;
use Froxlor\Api\ApiCommand;
use Froxlor\Api\ResourceEntity;
use Froxlor\Database\Database;
use Froxlor\Froxlor;
use Froxlor\FroxlorLogger;
use Froxlor\PhpHelper;
use Froxlor\Validate\Validate;
use PDO;
use PDOException;
class MysqlServer extends ApiCommand implements ResourceEntity
{
@@ -73,8 +74,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
* optional, test connection with given credentials, default is true (yes)
*
* @access admin
* @throws Exception
* @return string json-encoded array
* @throws Exception
*/
public function add()
{
@@ -112,7 +113,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
);
if (!empty($mysql_ca)) {
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool) $mysql_verifycert;
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool)$mysql_verifycert;
}
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
@@ -167,6 +168,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
$this->addDatabaseFromCustomerAllowedList($newdbserver);
}
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added new database server '" . $description . "' (" . $mysql_host . ")");
return $this->response(['dbserver' => $newdbserver]);
}
@@ -179,16 +182,16 @@ class MysqlServer extends ApiCommand implements ResourceEntity
* optional the number of the mysql server (either id or dbserver must be set)
*
* @access admin
* @throws Exception
* @return string json-encoded array
* @throws Exception
*/
public function delete()
{
$this->validateAccess();
$id = (int) $this->getParam('id', true, -1);
$id = (int)$this->getParam('id', true, -1);
$dn_optional = $id >= 0;
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
$dbserver = $id >= 0 ? $id : $dbserver;
if ($dbserver == 0) {
@@ -212,8 +215,12 @@ class MysqlServer extends ApiCommand implements ResourceEntity
// when removing, remove from list of allowed_mysqlservers from any customers
$this->removeDatabaseFromCustomerAllowedList($dbserver);
$description = $sql_root[$dbserver]['caption'] ?? "unknown";
$mysql_host = $sql_root[$dbserver]['host'] ?? "unknown";
unset($sql_root[$dbserver]);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] removed database server '" . $description . "' (" . $mysql_host . ")");
$this->generateNewUserData($sql, $sql_root);
return $this->response(['true']);
}
@@ -287,14 +294,14 @@ class MysqlServer extends ApiCommand implements ResourceEntity
* optional the number of the mysql server (either id or dbserver must be set)
*
* @access admin, customer
* @throws Exception
* @return string json-encoded array
* @throws Exception
*/
public function get()
{
$id = (int) $this->getParam('id', true, -1);
$id = (int)$this->getParam('id', true, -1);
$dn_optional = $id >= 0;
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
$dbserver = $id >= 0 ? $id : $dbserver;
$sql_root = [];
@@ -317,6 +324,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
unset($sql_root[$dbserver]['password']);
$sql_root[$dbserver]['id'] = $dbserver;
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get database-server '" . $sql_root[$dbserver]['caption'] . "'");
return $this->response($sql_root[$dbserver]);
}
@@ -347,16 +355,16 @@ class MysqlServer extends ApiCommand implements ResourceEntity
* optional, test connection with given credentials, default is true (yes)
*
* @access admin
* @throws Exception
* @return string json-encoded array
* @throws Exception
*/
public function update()
{
$this->validateAccess();
$id = (int) $this->getParam('id', true, -1);
$id = (int)$this->getParam('id', true, -1);
$dn_optional = $id >= 0;
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
$dbserver = $id >= 0 ? $id : $dbserver;
$sql_root = [];
@@ -417,7 +425,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
);
if (!empty($mysql_ca)) {
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool) $mysql_verifycert;
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool)$mysql_verifycert;
}
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
@@ -448,6 +456,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
$this->addDatabaseFromCustomerAllowedList($dbserver);
}
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] edited database server '" . $description . "' (" . $mysql_host . ")");
return $this->response(['true']);
}
@@ -472,7 +482,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
WHERE `dbserver` = :dbserver
");
$result = Database::pexecute_first($result_stmt, ['dbserver' => $dbserver], true, true);
return (int) $result['num_dbs'];
return (int)$result['num_dbs'];
} else {
$dbserver = $this->getParam('mysql_server');
$customer_ids = $this->getAllowedCustomerIds();

View File

@@ -199,7 +199,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
$this->mailer()->clearAddresses();
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] added mysql-database '" . $username . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added mysql-database '" . $username . "'");
$result = $this->apiCall('Mysqls.get', [
'dbname' => $username,
@@ -299,7 +299,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
$mbdata = $mbdata_stmt->fetch(PDO::FETCH_ASSOC);
Database::needRoot(false);
$result['size'] = $mbdata['MB'] ?? 0;
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get database '" . $result['databasename'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get database '" . $result['databasename'] . "'");
return $this->response($result);
}
$key = ($id > 0 ? "id #" . $id : "dbname '" . $dbname . "'");
@@ -388,7 +388,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
];
Database::pexecute($stmt, $params, true, true);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] updated mysql-database '" . $result['databasename'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated mysql-database '" . $result['databasename'] . "'");
$result = $this->apiCall('Mysqls.get', [
'dbname' => $result['databasename']
]);

View File

@@ -67,7 +67,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
public function listing()
{
if ($this->isAdmin()) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list php-configs");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list php-configs");
$with_subdomains = $this->getBoolParam('with_subdomains', true, false);
$query_fields = [];
@@ -392,7 +392,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
$ins_data['id'] = Database::lastInsertId();
Cronjob::inserttask(TaskId::REBUILD_VHOST);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
$result = $this->apiCall('PhpSettings.get', [
'id' => $ins_data['id']
@@ -629,7 +629,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
Database::pexecute($upd_stmt, $upd_data, true, true);
Cronjob::inserttask(TaskId::REBUILD_VHOST);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
$result = $this->apiCall('PhpSettings.get', [
'id' => $id
@@ -686,7 +686,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
], true, true);
Cronjob::inserttask(TaskId::REBUILD_VHOST);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
return $this->response($result);
}
throw new Exception("Not allowed to execute given command.", 403);

View File

@@ -229,6 +229,9 @@ class SubDomains extends ApiCommand implements ResourceEntity
} elseif ($completedomain_check && strtolower($completedomain_check['domain']) == strtolower($completedomain)) {
// the domain does already exist as main-domain
Response::standardError('domainexistalready', $completedomain, true);
} elseif ((int)$domain_check['deactivated'] == 1) {
// main domain is deactivated
Response::standardError('maindomaindeactivated', $domain, true);
}
// if allowed, check for 'is email domain'-flag
@@ -486,7 +489,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
}
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get subdomain '" . $result['domain'] . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get subdomain '" . $result['domain'] . "'");
return $this->response($result);
}
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
@@ -856,7 +859,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
Cronjob::inserttask(TaskId::REBUILD_VHOST);
Cronjob::inserttask(TaskId::REBUILD_DNS);
$idna_convert = new IdnaWrapper();
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'");
}
$result = $this->apiCall('SubDomains.get', [
'id' => $id
@@ -865,7 +868,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
}
/**
* lists all subdomain entries
* lists all customer domain/subdomain entries
*
* @param bool $with_ips
* optional, default true
@@ -910,17 +913,12 @@ class SubDomains extends ApiCommand implements ResourceEntity
$custom_list_result = $_custom_list_result['list'];
}
$customer_ids = [];
$customer_stdsubs = [];
foreach ($custom_list_result as $customer) {
$customer_ids[] = $customer['customerid'];
$customer_stdsubs[$customer['customerid']] = $customer['standardsubdomain'];
}
if (empty($customer_ids)) {
throw new Exception("Required resource unsatisfied.", 405);
}
if (empty($customer_stdsubs)) {
throw new Exception("Required resource unsatisfied.", 405);
}
$select_fields = [
'`d`.*'
@@ -932,9 +930,6 @@ class SubDomains extends ApiCommand implements ResourceEntity
$customer_ids = [
$this->getUserDetail('customerid')
];
$customer_stdsubs = [
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
];
$select_fields = [
'`d`.`id`',
@@ -949,7 +944,8 @@ class SubDomains extends ApiCommand implements ResourceEntity
'`d`.`parentdomainid`',
'`d`.`letsencrypt`',
'`d`.`registration_date`',
'`d`.`termination_date`'
'`d`.`termination_date`',
'`d`.`deactivated`'
];
}
$query_fields = [];
@@ -963,7 +959,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON `pd`.`id`=`d`.`parentdomainid`
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
AND `d`.`email_only` = '0'
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit());
" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit());
$result = [];
Database::pexecute($domains_stmt, $query_fields, true, true);

View File

@@ -92,7 +92,7 @@ class SysLog extends ApiCommand implements ResourceEntity
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list log-entries");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list log-entries");
return $this->response([
'count' => count($result),
'list' => $result

View File

@@ -166,7 +166,7 @@ class Traffic extends ApiCommand implements ResourceEntity
$row['mail'] *= 1024;
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list traffic");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list traffic");
return $this->response([
'count' => count($result),
'list' => $result

View File

@@ -112,11 +112,11 @@ class FroxlorRPC
*
* @return bool
*/
private static function validateAllowedFrom(array $allowed_from, string $remote_addr): bool
public static function validateAllowedFrom(array $allowed_from, string $remote_addr): bool
{
// shorten IP for comparison
$remote_addr = inet_ntop(inet_pton($remote_addr));
// check for diret matches
// check for direct matches
if (in_array($remote_addr, $allowed_from)) {
return true;
}

View File

@@ -166,6 +166,9 @@ final class MasterCron extends CliCommand
FroxlorLogger::getInstanceOf()->setCronLog(0);
}
// clean up possible old login-links
Database::query("DELETE FROM `" . TABLE_PANEL_LOGINLINKS . "` WHERE `valid_until` < UNIX_TIMESTAMP()");
return $result;
}

View File

@@ -62,8 +62,8 @@ class Bind extends DnsBase
$this->bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n";
foreach ($domains as $domain) {
if ($domain['ismainbutsubto'] > 0) {
// domains with ismainbutsubto>0 are handled by recursion within walkDomainList()
if ($domain['is_child']) {
// domains that are subdomains to other main domains are handled by recursion within walkDomainList()
continue;
}
$this->walkDomainList($domain, $domains);
@@ -114,7 +114,7 @@ class Bind extends DnsBase
$isFroxlorHostname = true;
}
if ($domain['ismainbutsubto'] == 0) {
if (!$domain['is_child']) {
$zoneContent = (string)Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
$domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone';
$zonefile_name = FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']);

View File

@@ -26,6 +26,7 @@
namespace Froxlor\Cron\Dns;
use Froxlor\Database\Database;
use Froxlor\Domain\Domain;
use Froxlor\FileDir;
use Froxlor\FroxlorLogger;
use Froxlor\PhpHelper;
@@ -210,7 +211,6 @@ abstract class DnsBase
`d`.`dkim`,
`d`.`dkim_id`,
`d`.`dkim_pubkey`,
`d`.`ismainbutsubto`,
`c`.`loginname`,
`c`.`guid`
FROM
@@ -219,7 +219,7 @@ abstract class DnsBase
WHERE
`d`.`isbinddomain` = '1'
ORDER BY
`d`.`domain` ASC
LENGTH(`d`.`domain`), `d`.`domain` ASC
");
$domains = [];
@@ -241,7 +241,6 @@ abstract class DnsBase
'bindserial' => date('Ymd') . '00',
'dkim' => '0',
'iswildcarddomain' => '1',
'ismainbutsubto' => '0',
'zonefile' => '',
'froxlorhost' => '1'
];
@@ -257,18 +256,23 @@ abstract class DnsBase
if (!isset($domains[$key]['children'])) {
$domains[$key]['children'] = [];
}
if ($domains[$key]['ismainbutsubto'] > 0) {
if (isset($domains[$domains[$key]['ismainbutsubto']])) {
$domains[$domains[$key]['ismainbutsubto']]['children'][] = $domains[$key]['id'];
} else {
$domains[$key]['ismainbutsubto'] = 0;
if (!isset($domains[$key]['is_child'])) {
$domains[$key]['is_child'] = false;
}
$children = Domain::getMainSubdomainIds($key);
if (count($children) > 0) {
foreach ($children as $child) {
if (isset($domains[$child])) {
$domains[$key]['children'][] = $domains[$child]['id'];
$domains[$child]['is_child'] = true;
}
}
}
}
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, str_pad('domId', 9, ' ') . str_pad('domain', 40, ' ') . 'ismainbutsubto ' . str_pad('parent domain', 40, ' ') . "list of child domain ids");
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, str_pad('domId', 9, ' ') . str_pad('domain', 40, ' ') . "list of child domain ids");
foreach ($domains as $domain) {
$logLine = str_pad($domain['id'], 9, ' ') . str_pad($domain['domain'], 40, ' ') . str_pad($domain['ismainbutsubto'], 15, ' ') . str_pad(((isset($domains[$domain['ismainbutsubto']])) ? $domains[$domain['ismainbutsubto']]['domain'] : '-'), 40, ' ') . join(', ', $domain['children']);
$logLine = str_pad($domain['id'], 9, ' ') . str_pad($domain['domain'], 40, ' ') . join(', ', $domain['children']);
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, $logLine);
}

View File

@@ -50,8 +50,8 @@ class PowerDNS extends DnsBase
}
foreach ($domains as $domain) {
if ($domain['ismainbutsubto'] > 0) {
// domains with ismainbutsubto>0 are handled by recursion within walkDomainList()
if ($domain['is_child']) {
// domains that are subdomains to other main domains are handled by recursion within walkDomainList()
continue;
}
$this->walkDomainList($domain, $domains);
@@ -108,7 +108,7 @@ class PowerDNS extends DnsBase
$isFroxlorHostname = true;
}
if ($domain['ismainbutsubto'] == 0) {
if (!$domain['is_child']) {
$zoneContent = Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
if (count($subzones)) {
foreach ($subzones as $subzone) {

View File

@@ -630,29 +630,6 @@ class Apache extends HttpConfigBase
}
}
/**
* Get the filename for the virtualhost
*/
protected function getVhostFilename($domain, $ssl_vhost = false)
{
if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) {
$vhost_no = '35';
} elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) {
$vhost_no = '30';
} else {
// number of dots in a domain specifies it's position (and depth of subdomain) starting at 29 going downwards on higher depth
$vhost_no = (string)(30 - substr_count($domain['domain'], ".") + 1);
}
if ($ssl_vhost === true) {
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_ssl_vhost_' . $domain['domain'] . '.conf');
} else {
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_normal_vhost_' . $domain['domain'] . '.conf');
}
return $vhost_filename;
}
/**
* We compose the virtualhost entry for one domain
*/

View File

@@ -28,6 +28,7 @@ namespace Froxlor\Cron\Http;
use Froxlor\Cron\Http\LetsEncrypt\AcmeSh;
use Froxlor\Cron\Http\Php\Fpm;
use Froxlor\Database\Database;
use Froxlor\Domain\Domain;
use Froxlor\FileDir;
use Froxlor\Froxlor;
use Froxlor\FroxlorLogger;
@@ -187,4 +188,18 @@ class HttpConfigBase
}
return false;
}
/**
* Get the filename for the virtualhost
*/
protected function getVhostFilename(array $domain, bool $ssl_vhost = false, bool $filename_only = false)
{
// number of dots in a domain specifies its position (and depth of subdomain) starting at 35 going downwards on higher depth
$vhost_no = (string)(35 - substr_count($domain['domain'], ".") + 1);
$filename = $vhost_no . '_froxlor_' . ($ssl_vhost ? 'ssl' : 'normal') . '_vhost_' . $domain['domain'] . '.conf';
if ($filename_only) {
return $filename;
}
return FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $filename);
}
}

View File

@@ -336,24 +336,9 @@ class Lighttpd extends HttpConfigBase
$_pos = strrpos($_tmp_path, '/');
$_inc_path = substr($_tmp_path, $_pos + 1);
// maindomain
if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) {
$vhost_no = '50';
} elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) {
// sub-but-main-domain
$vhost_no = '51';
} else {
// subdomains
// number of dots in a domain specifies it's position (and depth of subdomain) starting at 89 going downwards on higher depth
$vhost_no = (string)(90 - substr_count($domain['domain'], ".") + 1);
}
if ($ssl == '1') {
$vhost_no = (int)$vhost_no += 10;
}
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/vhosts/' . $vhost_no . '_' . $domain['domain'] . '.conf');
$included_vhosts[] = $_inc_path . '/vhosts/' . $vhost_no . '_' . $domain['domain'] . '.conf';
$filename = self::getVhostFilename($domain, ($ssl == '1'), true);
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/vhosts/' . $filename);
$included_vhosts[] = $_inc_path . '/vhosts/' . $filename;
}
if (!isset($this->lighttpd_data[$vhost_filename])) {

View File

@@ -225,7 +225,7 @@ class Nginx extends HttpConfigBase
$this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n";
// protect bin/
$this->nginx_data[$vhost_filename] .= "\t" . 'location ~ ' . rtrim($relpath, "/") . '/(bin|cache|logs|tests|vendor) {' . "\n";
$this->nginx_data[$vhost_filename] .= "\t" . 'location ~ ^' . rtrim($relpath, "/") . '/(bin|cache|logs|tests|vendor) {' . "\n";
$this->nginx_data[$vhost_filename] .= "\t" . ' deny all;' . "\n";
$this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n";
}
@@ -467,26 +467,6 @@ class Nginx extends HttpConfigBase
}
}
protected function getVhostFilename($domain, $ssl_vhost = false)
{
if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) {
$vhost_no = '35';
} elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) {
$vhost_no = '30';
} else {
// number of dots in a domain specifies it's position (and depth of subdomain) starting at 29 going downwards on higher depth
$vhost_no = (string)(30 - substr_count($domain['domain'], ".") + 1);
}
if ($ssl_vhost === true) {
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_ssl_vhost_' . $domain['domain'] . '.conf');
} else {
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_normal_vhost_' . $domain['domain'] . '.conf');
}
return $vhost_filename;
}
protected function getVhostContent($domain, $ssl_vhost = false)
{
if ($ssl_vhost === true && $domain['ssl'] != '1' && $domain['ssl_redirect'] != '1') {

View File

@@ -289,7 +289,7 @@ pm.max_children = 1
}
}
// now check if 'sendmail_path' has not beed set in the custom-php.ini
// now check if 'sendmail_path' has not been set in the custom-php.ini
// if not we use our fallback-default as usual
if (strpos($fpm_config, 'php_admin_value[sendmail_path]') === false) {
$fpm_config .= 'php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f ' . $this->domain['email'] . "\n";

View File

@@ -25,10 +25,10 @@
namespace Froxlor;
use Froxlor\Database\Database;
use Froxlor\UI\Collection;
use Froxlor\Api\Commands\Customers;
use Froxlor\Api\Commands\SubDomains;
use Froxlor\Database\Database;
use Froxlor\UI\Collection;
/**
* Class to manage the current user / session
@@ -144,22 +144,29 @@ class CurrentUser
$result_stmt = Database::prepare("
SELECT COUNT(`id`) as emaildomains
FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `customerid`= :cid AND `isemaildomain` = '1'
WHERE `customerid`= :cid AND `isemaildomain` = '1' AND `deactivated` = '0'
");
$result = Database::pexecute_first($result_stmt, [
"cid" => $_SESSION['userinfo']['customerid']
]);
$addition = $result['emaildomains'] != 0;
} elseif ($resource == 'subdomains') {
$parentDomainCollection = (new Collection(SubDomains::class, $_SESSION['userinfo'],
['sql_search' => ['d.parentdomainid' => 0]]));
$addition = $parentDomainCollection != 0;
$parentDomainCollection = (new Collection(
SubDomains::class,
$_SESSION['userinfo'],
['sql_search' => [
'd.parentdomainid' => 0,
'd.deactivated' => 0,
'd.id' => ['op' => '<>', 'value' => $_SESSION['userinfo']['standardsubdomain']]
]
]
));
$addition = $parentDomainCollection->count() != 0;
} elseif ($resource == 'domains') {
$customerCollection = (new Collection(Customers::class, $_SESSION['userinfo']));
$addition = $customerCollection != 0;
$addition = $customerCollection->count() != 0;
}
return ($_SESSION['userinfo'][$resource . '_used'] < $_SESSION['userinfo'][$resource] || $_SESSION['userinfo'][$resource] == '-1') && $addition;
}
}

View File

@@ -235,51 +235,30 @@ class Domain
}
/**
* check whether a domain has subdomains added as full-domains
* #329
* get ids of domains that are main domains but a subdomain of another main domain (for DNS)
*
* @param int $id domain-id
* @param int $id main-domain to check
*
* @return bool
* @return array
* @throws \Exception
*/
public static function domainHasMainSubDomains(int $id): bool
public static function getMainSubdomainIds(int $id): array
{
$result_stmt = Database::prepare("
SELECT COUNT(`id`) as `mainsubs` FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `ismainbutsubto` = :id");
$result = Database::pexecute_first($result_stmt, [
'id' => $id
]);
if ($result && isset($result['mainsubs'])) {
return $result['mainsubs'] > 0;
}
return false;
}
/**
* check whether a subof-domain exists
* #329
*
* @param int $id subof-domain-id
*
* @return bool
* @throws \Exception
*/
public static function domainMainToSubExists(int $id): bool
{
$result_stmt = Database::prepare("
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `id` = :id");
SELECT id
FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE
isbinddomain = 1 AND
domain LIKE CONCAT('%.', ( SELECT d.domain FROM `" . TABLE_PANEL_DOMAINS . "` AS d WHERE d.id = :id ))
");
Database::pexecute($result_stmt, [
'id' => $id
]);
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
if ($result && isset($result['id'])) {
return $result['id'] > 0;
$result = [];
while ($entry = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$result = $entry['id'];
}
return false;
return $result;
}
/**

View File

@@ -31,10 +31,10 @@ final class Froxlor
{
// Main version variable
const VERSION = '2.0.19';
const VERSION = '2.1.0-dev1';
// Database version (YYYYMMDDC where C is a daily counter)
const DBVERSION = '202304260';
const DBVERSION = '202305240';
// Distribution branding-tag (used for Debian etc.)
const BRANDING = '';

View File

@@ -421,6 +421,7 @@ class Core
$this->updateSetting($upd_stmt, $this->validatedData['activate_newsfeed'], 'admin', 'show_news_feed');
$this->updateSetting($upd_stmt, dirname(__FILE__, 5), 'system', 'letsencryptchallengepath');
$this->updateSetting($upd_stmt, dirname(__FILE__, 5) . '/templates/misc/deactivated/', 'system', 'deactivateddocroot');
// insert the lastcronrun to be the installation date
$this->updateSetting($upd_stmt, time(), 'system', 'lastcronrun');

View File

@@ -51,6 +51,9 @@ class Domain
public static function domainTarget(array $attributes)
{
if (empty($attributes['fields']['aliasdomain'])) {
if ($attributes['fields']['deactivated']) {
return lng('admin.deactivated');
}
// path or redirect
if (preg_match('/^https?\:\/\//', $attributes['fields']['documentroot'])) {
return [
@@ -80,7 +83,7 @@ class Domain
}
$result .= '<a href="http://' . $attributes['data'] . '" target="_blank">' . $attributes['data'] . '</a>';
// check for statistics if parentdomainid==0 to show stats-link for customers
if ((int)UI::getCurrentUser()['adminsession'] == 0 && $attributes['fields']['parentdomainid'] == 0) {
if ((int)UI::getCurrentUser()['adminsession'] == 0 && $attributes['fields']['parentdomainid'] == 0 && $attributes['fields']['deactivated'] == 0) {
$statsapp = Settings::Get('system.traffictool');
$result .= ' <a href="http://' . $attributes['data'] . '/' . $statsapp . '" rel="external" target="_blank" title="' . lng('domains.statstics') . '"><i class="fa-solid fa-chart-line text-secondary"></i></a>';
}
@@ -95,12 +98,12 @@ class Domain
public static function canEdit(array $attributes): bool
{
return (bool)$attributes['fields']['caneditdomain'];
return (bool)($attributes['fields']['caneditdomain'] && !$attributes['fields']['deactivated']);
}
public static function canViewLogs(array $attributes): bool
{
if ((int)$attributes['fields']['email_only'] == 0) {
if ((int)$attributes['fields']['email_only'] == 0 && !$attributes['fields']['deactivated']) {
if ((int)UI::getCurrentUser()['adminsession'] == 0 && (bool)UI::getCurrentUser()['logviewenabled']) {
return true;
} elseif ((int)UI::getCurrentUser()['adminsession'] == 1) {
@@ -129,7 +132,8 @@ class Domain
&& UI::getCurrentUser()['dnsenabled'] == '1'
&& $attributes['fields']['caneditdomain'] == '1'
&& Settings::Get('system.bind_enable') == '1'
&& Settings::Get('system.dnsenabled') == '1';
&& Settings::Get('system.dnsenabled') == '1'
&& !$attributes['fields']['deactivated'];
}
public static function adminCanEditDNS(array $attributes): bool
@@ -152,6 +156,7 @@ class Domain
&& (int)$attributes['fields']['caneditdomain'] == 1
&& (int)$attributes['fields']['letsencrypt'] == 0
&& (int)$attributes['fields']['email_only'] == 0
&& !$attributes['fields']['deactivated']
) {
return true;
}

View File

@@ -60,17 +60,18 @@ class Style
$today = time();
$termination_css = 'bg-warning';
if ($cdate < $today) {
$termination_css = 'bg-danger';
$termination_css = 'bg-danger text-light';
}
}
return $attributes['fields']['deactivated'] ? 'bg-info' : $termination_css;
$deactivated = $attributes['fields']['deactivated'] || $attributes['fields']['customer_deactivated'];
return $deactivated ? 'bg-info text-light' : $termination_css;
}
public static function resultCustomerLockedOrDeactivated(array $attributes): string
{
$row_css = '';
if ((int)$attributes['fields']['deactivated'] == 1) {
$row_css = 'bg-info';
$row_css = 'bg-info text-light';
} elseif (
$attributes['fields']['loginfail_count'] >= Settings::Get('login.maxloginattempts')
&& $attributes['fields']['lastlogin_fail'] > (time() - Settings::Get('login.deactivatetime'))

View File

@@ -25,10 +25,13 @@
namespace Froxlor\UI\Callbacks;
use Froxlor\CurrentUser;
use Froxlor\Database\Database;
use Froxlor\Froxlor;
use Froxlor\PhpHelper;
use Froxlor\UI\Panel\UI;
use Froxlor\User;
use PDO;
class Text
{
@@ -105,4 +108,44 @@ class Text
'body' => $body
];
}
public static function domainDuplicateModal(array $attributes): array
{
$linker = UI::getLinker();
$result = $attributes['fields'];
$customers = [
0 => lng('panel.please_choose')
];
$result_customers_stmt = Database::prepare("
SELECT `customerid`, `loginname`, `name`, `firstname`, `company`
FROM `" . TABLE_PANEL_CUSTOMERS . "` " . (CurrentUser::getField('customers_see_all') ? '' : " WHERE `adminid` = :adminid ") . "
ORDER BY COALESCE(NULLIF(`name`,''), `company`) ASC
");
$params = [];
if (CurrentUser::getField('customers_see_all') == '0') {
$params['adminid'] = CurrentUser::getField('adminid');
}
Database::pexecute($result_customers_stmt, $params);
while ($row_customer = $result_customers_stmt->fetch(PDO::FETCH_ASSOC)) {
$customers[$row_customer['customerid']] = User::getCorrectFullUserDetails($row_customer) . ' (' . $row_customer['loginname'] . ')';
}
$domdup_data = include Froxlor::getInstallDir() . '/lib/formfields/admin/domains/formfield.domains_duplicate.php';
$body = UI::twig()->render(UI::validateThemeTemplate('/user/inline-form.html.twig'), [
'formaction' => $linker->getLink(['section' => 'domains', 'page' => 'domains', 'action' => 'duplicate']),
'formdata' => $domdup_data['domain_duplicate'],
'editid' => $attributes['fields']['id'],
'nosubmit' => 0
]);
return [
'entry' => $attributes['fields']['id'],
'id' => 'ddModal' . $attributes['fields']['id'],
'title' => lng('admin.domain_duplicate_named', [$attributes['fields']['domain']]),
'action' => 'duplicate',
'body' => $body
];
}
}

View File

@@ -230,6 +230,7 @@ class Listing
'label' => $coldata['label'],
'checked' => in_array($column, $tabellisting['visible_columns']),
'searchable' => $coldata['searchable'] ?? true,
'isdefaultsearchfield' => $coldata['isdefaultsearchfield'] ?? false,
];
}
}

View File

@@ -52,16 +52,16 @@ class Check
];
$check_array = [
'system_mod_fcgid_enabled' => [
'other_post_field' => 'system_phpfpm_enabled',
'system_mod_fcgid' => [
'other_post_field' => 'phpfpm_enabled',
'other_enabled' => 'phpfpm.enabled',
'other_enabled_lng' => 'phpfpmstillenabled',
'deactivate' => [
'phpfpm.enabled_ownvhost' => 0
]
],
'system_phpfpm_enabled' => [
'other_post_field' => 'system_mod_fcgid_enabled',
'phpfpm_enabled' => [
'other_post_field' => 'system_mod_fcgid',
'other_enabled' => 'system.mod_fcgid',
'other_enabled_lng' => 'fcgidstillenabled',
'deactivate' => [