major refactoring of almost all files

This commit is contained in:
envoyr
2022-04-28 20:48:00 +02:00
parent a2e95b960f
commit 4f4c71d79b
285 changed files with 21716 additions and 18766 deletions

View File

@@ -11,68 +11,80 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can also view it online at
* http://files.froxlor.org/misc/COPYING.txt
* https://files.froxlor.org/misc/COPYING.txt
*
* @copyright the authors
* @author Froxlor team <team@froxlor.org>
* @license http://files.froxlor.org/misc/COPYING.txt GPLv2
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/
namespace Froxlor\Api;
use Exception;
use Froxlor\Database\Database;
use Froxlor\Froxlor;
use Froxlor\FroxlorLogger;
use Froxlor\Language;
use Froxlor\System\Mailer;
use Froxlor\Settings;
use Froxlor\Api\Response;
use Froxlor\PhpHelper;
use Froxlor\Database\Database;
use Froxlor\Settings;
use Froxlor\System\Mailer;
abstract class ApiCommand extends ApiParameter
{
/**
* froxlor version
*
* @var string
*/
protected $version = null;
/**
* froxlor dbversion
*
* @var int
*/
protected $dbversion = null;
/**
* froxlor version-branding
*
* @var string
*/
protected $branding = null;
/**
* debug flag
*
* @var boolean
*/
private $debug = false;
/**
* is admin flag
*
* @var boolean
*/
private $is_admin = false;
/**
* internal user data array
*
* @var array
*/
private $user_data = null;
/**
* logger interface
*
* @var \Froxlor\FroxlorLogger
* @var FroxlorLogger
*/
private $logger = null;
/**
* mail interface
*
* @var \Froxlor\System\Mailer
* @var Mailer
*/
private $mail = null;
/**
* whether the call is an internal one or not
*
@@ -80,39 +92,18 @@ abstract class ApiCommand extends ApiParameter
*/
private $internal_call = false;
/**
* froxlor version
*
* @var string
*/
protected $version = null;
/**
* froxlor dbversion
*
* @var int
*/
protected $dbversion = null;
/**
* froxlor version-branding
*
* @var string
*/
protected $branding = null;
/**
*
* @param array $header
* optional, passed via API
* optional, passed via API
* @param array $params
* optional, array of parameters (var=>value) for the command
* optional, array of parameters (var=>value) for the command
* @param array $userinfo
* optional, passed via WebInterface (instead of $header)
* optional, passed via WebInterface (instead of $header)
* @param boolean $internal
* optional whether called internally, default false
*
* @throws \Exception
* optional whether called internally, default false
*
* @throws Exception
*/
public function __construct($header = null, $params = null, $userinfo = null, $internal = false)
{
@@ -154,57 +145,45 @@ abstract class ApiCommand extends ApiParameter
}
/**
* initialize language to have localized strings available for the ApiCommands
* read user data from database by api-request-header fields
*
* @param array $header
* api-request header
*
* @return boolean
* @throws Exception
*/
private function initLang()
private function readUserData($header = null)
{
Language::setLanguage(Settings::Get('panel.standardlanguage'));
if ($this->getUserDetail('language') !== null && isset(Language::getLanguages()[$this->getUserDetail('language')])) {
Language::setLanguage($this->getUserDetail('language'));
} elseif ($this->getUserDetail('def_language') !== null) {
Language::setLanguage($this->getUserDetail('def_language'));
$sel_stmt = Database::prepare("SELECT * FROM `api_keys` WHERE `apikey` = :ak AND `secret` = :as");
$result = Database::pexecute_first($sel_stmt, [
'ak' => $header['apikey'],
'as' => $header['secret']
], true, true);
if ($result) {
// admin or customer?
if ($result['customerid'] == 0 && $result['adminid'] > 0) {
$this->is_admin = true;
$table = 'panel_admins';
$key = "adminid";
} elseif ($result['customerid'] > 0 && $result['adminid'] > 0) {
$this->is_admin = false;
$table = 'panel_customers';
$key = "customerid";
} else {
// neither adminid is > 0 nor customerid is > 0 - sorry man, no way
throw new Exception("Invalid API credentials", 400);
}
$sel_stmt = Database::prepare("SELECT * FROM `" . $table . "` WHERE `" . $key . "` = :id");
$this->user_data = Database::pexecute_first($sel_stmt, [
'id' => ($this->is_admin ? $result['adminid'] : $result['customerid'])
], true, true);
if ($this->is_admin) {
$this->user_data['adminsession'] = 1;
}
return true;
}
}
/**
* returns an instance of the wanted ApiCommand (e.g.
* Customers, Domains, etc);
* this is used widely in the WebInterface
*
* @param array $userinfo
* array of user-data
* @param array $params
* array of parameters for the command
* @param boolean $internal
* optional whether called internally, default false
*
* @return ApiCommand
* @throws \Exception
*/
public static function getLocal($userinfo = null, $params = null, $internal = false)
{
return new static(null, $params, $userinfo, $internal);
}
/**
* admin flag
*
* @return boolean
*/
protected function isAdmin()
{
return $this->is_admin;
}
/**
* internal call flag
*
* @return boolean
*/
protected function isInternal()
{
return $this->internal_call;
throw new Exception("Invalid API credentials", 400);
}
/**
@@ -220,30 +199,69 @@ abstract class ApiCommand extends ApiParameter
}
/**
* return user-data array
* return logger instance
*
* @return array
* @return FroxlorLogger
*/
protected function getUserData()
protected function logger()
{
return $this->user_data;
return $this->logger;
}
/**
* initialize language to have localized strings available for the ApiCommands
*/
private function initLang()
{
Language::setLanguage(Settings::Get('panel.standardlanguage'));
if ($this->getUserDetail('language') !== null && isset(Language::getLanguages()[$this->getUserDetail('language')])) {
Language::setLanguage($this->getUserDetail('language'));
} elseif ($this->getUserDetail('def_language') !== null) {
Language::setLanguage($this->getUserDetail('def_language'));
}
}
/**
* increase/decrease a resource field for customers/admins
*
* @param string $table
* @param string $keyfield
* @param int $key
* @param string $operator
* @param string $resource
* @param string $extra
* @param int $step
*/
protected static function updateResourceUsage($table = null, $keyfield = null, $key = null, $operator = '+', $resource = null, $extra = null, $step = 1)
{
$stmt = Database::prepare("
UPDATE `" . $table . "`
SET `" . $resource . "` = `" . $resource . "` " . $operator . " " . (int)$step . " " . $extra . "
WHERE `" . $keyfield . "` = :key
");
Database::pexecute($stmt, [
'key' => $key
], true, true);
}
/**
* return SQL when parameter $sql_search is given via API
*
* @param array $sql_search
* optional array with index = fieldname, and value = array with 'op' => operator (one of <, > or =), LIKE is used if left empty and 'value' => searchvalue
* optional array with index = fieldname, and value = array with 'op' => operator (one of <, > or =),
* LIKE is used if left empty and 'value' => searchvalue
* @param array $query_fields
* optional array of placeholders mapped to the actual value which is used in the API commands when executing the statement [internal]
* optional array of placeholders mapped to the actual value which is used in the API commands when
* executing the statement [internal]
* @param boolean $append
* optional append to WHERE clause rather then create new one, default false [internal]
*
* optional append to WHERE clause rather then create new one, default false [internal]
*
* @return string
*/
protected function getSearchWhere(&$query_fields = array(), $append = false)
protected function getSearchWhere(&$query_fields = [], $append = false)
{
$search = $this->getParam('sql_search', true, array());
$search = $this->getParam('sql_search', true, []);
$condition = '';
if (!empty($search)) {
if ($append == true) {
@@ -251,11 +269,11 @@ abstract class ApiCommand extends ApiParameter
} else {
$condition = ' WHERE ';
}
$ops = array(
$ops = [
'<',
'>',
'='
);
];
$first = true;
foreach ($search as $field => $valoper) {
if ($field == '_plainsql') {
@@ -330,10 +348,10 @@ abstract class ApiCommand extends ApiParameter
* return LIMIT clause when at least $sql_limit parameter is given via API
*
* @param int $sql_limit
* optional, limit resultset, default 0
* optional, limit resultset, default 0
* @param int $sql_offset
* optional, offset for limitation, default 0
*
* optional, offset for limitation, default 0
*
* @return string
*/
protected function getLimit()
@@ -359,15 +377,15 @@ abstract class ApiCommand extends ApiParameter
* return ORDER BY clause if parameter $sql_orderby parameter is given via API
*
* @param array $sql_orderby
* optional array with index = fieldname and value = ASC|DESC
* optional array with index = fieldname and value = ASC|DESC
* @param boolean $append
* optional append to ORDER BY clause rather then create new one, default false [internal]
*
* optional append to ORDER BY clause rather then create new one, default false [internal]
*
* @return string
*/
protected function getOrderBy($append = false)
{
$orderby = $this->getParam('sql_orderby', true, array());
$orderby = $this->getParam('sql_orderby', true, []);
$order = "";
if (!empty($orderby)) {
if ($append) {
@@ -425,46 +443,16 @@ abstract class ApiCommand extends ApiParameter
return $order;
}
/**
* return logger instance
*
* @return \Froxlor\FroxlorLogger
*/
protected function logger()
{
return $this->logger;
}
/**
* return mailer instance
*
* @return \Froxlor\System\Mailer
* @return Mailer
*/
protected function mailer()
{
return $this->mail;
}
/**
* call an api-command internally
*
* @param string $command
* @param array|null $params
* @param boolean $internal
* optional whether called internally, default false
*
*
* @return array
*/
protected function apiCall($command = null, $params = null, $internal = false)
{
$_command = explode(".", $command);
$module = __NAMESPACE__ . "\Commands\\" . $_command[0];
$function = $_command[1];
$json_result = $module::getLocal($this->getUserData(), $params, $internal)->{$function}();
return json_decode($json_result, true)['data'];
}
/**
* return api-compatible response in JSON format and send corresponding http-header
*
@@ -481,14 +469,15 @@ abstract class ApiCommand extends ApiParameter
* returns an array of customers the current user can access
*
* @param string $customer_hide_option
* optional, when called as customer, some options might be hidden due to the panel.customer_hide_options ettings
*
* @throws \Exception
* optional, when called as customer, some options might be hidden due to the
* panel.customer_hide_options ettings
*
* @return array
* @throws Exception
*/
protected function getAllowedCustomerIds($customer_hide_option = '')
{
$customer_ids = array();
$customer_ids = [];
if ($this->isAdmin()) {
// if we're an admin, list all ftp-users of all the admins customers
// or optionally for one specific customer identified by id or loginname
@@ -496,13 +485,13 @@ abstract class ApiCommand extends ApiParameter
$loginname = $this->getParam('loginname', true, '');
if (!empty($customerid) || !empty($loginname)) {
$_result = $this->apiCall('Customers.get', array(
$_result = $this->apiCall('Customers.get', [
'id' => $customerid,
'loginname' => $loginname
));
$custom_list_result = array(
]);
$custom_list_result = [
$_result
);
];
} else {
$_custom_list_result = $this->apiCall('Customers.listing');
$custom_list_result = $_custom_list_result['list'];
@@ -514,9 +503,9 @@ abstract class ApiCommand extends ApiParameter
if (!$this->isInternal() && !empty($customer_hide_option) && Settings::IsInList('panel.customer_hide_options', $customer_hide_option)) {
throw new Exception("You cannot access this resource", 405);
}
$customer_ids = array(
$customer_ids = [
$this->getUserDetail('customerid')
);
];
}
if (empty($customer_ids)) {
throw new Exception("Required resource unsatisfied.", 405);
@@ -524,28 +513,98 @@ abstract class ApiCommand extends ApiParameter
return $customer_ids;
}
/**
* admin flag
*
* @return boolean
*/
protected function isAdmin()
{
return $this->is_admin;
}
/**
* call an api-command internally
*
* @param string $command
* @param array|null $params
* @param boolean $internal
* optional whether called internally, default false
*
*
* @return array
*/
protected function apiCall($command = null, $params = null, $internal = false)
{
$_command = explode(".", $command);
$module = __NAMESPACE__ . "\Commands\\" . $_command[0];
$function = $_command[1];
$json_result = $module::getLocal($this->getUserData(), $params, $internal)->{$function}();
return json_decode($json_result, true)['data'];
}
/**
* returns an instance of the wanted ApiCommand (e.g.
* Customers, Domains, etc);
* this is used widely in the WebInterface
*
* @param array $userinfo
* array of user-data
* @param array $params
* array of parameters for the command
* @param boolean $internal
* optional whether called internally, default false
*
* @return ApiCommand
* @throws Exception
*/
public static function getLocal($userinfo = null, $params = null, $internal = false)
{
return new static(null, $params, $userinfo, $internal);
}
/**
* return user-data array
*
* @return array
*/
protected function getUserData()
{
return $this->user_data;
}
/**
* internal call flag
*
* @return boolean
*/
protected function isInternal()
{
return $this->internal_call;
}
/**
* returns an array of customer data for customer, or by customer-id/loginname for admin/reseller
*
* @param int $customerid
* optional, required if loginname is empty
* optional, required if loginname is empty
* @param string $loginname
* optional, required of customerid is empty
* optional, required of customerid is empty
* @param string $customer_resource_check
* optional, when called as admin, check the resources of the target customer
*
* @throws \Exception
* optional, when called as admin, check the resources of the target customer
*
* @return array
* @throws Exception
*/
protected function getCustomerData($customer_resource_check = '')
{
if ($this->isAdmin()) {
$customerid = $this->getParam('customerid', true, 0);
$loginname = $this->getParam('loginname', true, '');
$customer = $this->apiCall('Customers.get', array(
$customer = $this->apiCall('Customers.get', [
'id' => $customerid,
'loginname' => $loginname
));
]);
// check whether the customer has enough resources
if (!empty($customer_resource_check) && $customer[$customer_resource_check . '_used'] >= $customer[$customer_resource_check] && $customer[$customer_resource_check] != '-1') {
throw new Exception("Customer has no more resources available", 406);
@@ -556,29 +615,6 @@ abstract class ApiCommand extends ApiParameter
return $customer;
}
/**
* increase/decrease a resource field for customers/admins
*
* @param string $table
* @param string $keyfield
* @param int $key
* @param string $operator
* @param string $resource
* @param string $extra
* @param int $step
*/
protected static function updateResourceUsage($table = null, $keyfield = null, $key = null, $operator = '+', $resource = null, $extra = null, $step = 1)
{
$stmt = Database::prepare("
UPDATE `" . $table . "`
SET `" . $resource . "` = `" . $resource . "` " . $operator . " " . (int) $step . " " . $extra . "
WHERE `" . $keyfield . "` = :key
");
Database::pexecute($stmt, array(
'key' => $key
), true, true);
}
/**
* return email template content from database or global language file if not found in DB
*
@@ -590,19 +626,19 @@ abstract class ApiCommand extends ApiParameter
*
* @return string
*/
protected function getMailTemplate($customerdata = null, $group = null, $varname = null, $replace_arr = array(), $default = "")
protected function getMailTemplate($customerdata = null, $group = null, $varname = null, $replace_arr = [], $default = "")
{
// get template
$stmt = Database::prepare("
SELECT `value` FROM `" . TABLE_PANEL_TEMPLATES . "` WHERE `adminid`= :adminid
AND `language`= :lang AND `templategroup`= :group AND `varname`= :var
");
$result = Database::pexecute_first($stmt, array(
$result = Database::pexecute_first($stmt, [
"adminid" => $customerdata['adminid'],
"lang" => $customerdata['def_language'],
"group" => $group,
"var" => $varname
), true, true);
], true, true);
$content = $default;
if ($result) {
$content = $result['value'] ?? $default;
@@ -611,46 +647,4 @@ abstract class ApiCommand extends ApiParameter
$content = html_entity_decode(PhpHelper::replaceVariables($content, $replace_arr));
return $content;
}
/**
* read user data from database by api-request-header fields
*
* @param array $header
* api-request header
*
* @throws \Exception
* @return boolean
*/
private function readUserData($header = null)
{
$sel_stmt = Database::prepare("SELECT * FROM `api_keys` WHERE `apikey` = :ak AND `secret` = :as");
$result = Database::pexecute_first($sel_stmt, array(
'ak' => $header['apikey'],
'as' => $header['secret']
), true, true);
if ($result) {
// admin or customer?
if ($result['customerid'] == 0 && $result['adminid'] > 0) {
$this->is_admin = true;
$table = 'panel_admins';
$key = "adminid";
} elseif ($result['customerid'] > 0 && $result['adminid'] > 0) {
$this->is_admin = false;
$table = 'panel_customers';
$key = "customerid";
} else {
// neither adminid is > 0 nor customerid is > 0 - sorry man, no way
throw new Exception("Invalid API credentials", 400);
}
$sel_stmt = Database::prepare("SELECT * FROM `" . $table . "` WHERE `" . $key . "` = :id");
$this->user_data = Database::pexecute_first($sel_stmt, array(
'id' => ($this->is_admin ? $result['adminid'] : $result['customerid'])
), true, true);
if ($this->is_admin) {
$this->user_data['adminsession'] = 1;
}
return true;
}
throw new Exception("Invalid API credentials", 400);
}
}