don't send header() on CLI environment

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
Michael Kaufmann
2022-02-25 15:16:59 +01:00
parent 1faa9f17ab
commit d933549646
3 changed files with 96 additions and 98 deletions

View File

@@ -19,13 +19,13 @@ if (! defined('AREA')) {
* *
*/ */
use Froxlor\Api\Commands\DomainZones as DomainZones; use Froxlor\Api\Commands\DomainZones;
use Froxlor\UI\Request; use Froxlor\UI\Request;
// This file is being included in admin_domains and customer_domains // This file is being included in admin_domains and customer_domains
// and therefore does not need to require lib/init.php // and therefore does not need to require lib/init.php
$domain_id = (int) Request::get(['domain_id']); $domain_id = (int) Request::get('domain_id');
$record = isset($_POST['record']['record']) ? trim($_POST['record']['record']) : null; $record = isset($_POST['record']['record']) ? trim($_POST['record']['record']) : null;
$type = isset($_POST['record']['type']) ? $_POST['record']['type'] : 'A'; $type = isset($_POST['record']['type']) ? $_POST['record']['type'] : 'A';

View File

@@ -3,7 +3,6 @@
namespace Froxlor\Api; namespace Froxlor\Api;
use Exception; use Exception;
use voku\helper\AntiXSS;
/** /**
* This file is part of the Froxlor project. * This file is part of the Froxlor project.
@@ -23,110 +22,111 @@ use voku\helper\AntiXSS;
*/ */
class FroxlorRPC class FroxlorRPC
{ {
/** /**
* validate a given request * validate a given request
* *
* @param $request * @param $request
* @return array * @return array
* @throws Exception * @throws Exception
*/ */
public static function validateRequest($request): array public static function validateRequest($request): array
{ {
// make basic authentication // make basic authentication
if (!isset($_SERVER['PHP_AUTH_USER']) || !self::validateAuth($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) { if (!isset($_SERVER['PHP_AUTH_USER']) || !self::validateAuth($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
header('WWW-Authenticate: Basic realm="API"'); if (@php_sapi_name() !== 'cli') {
throw new Exception('Unauthenticated. Please provide api user credentials.', 401); header('WWW-Authenticate: Basic realm="API"');
} }
throw new Exception('Unauthenticated. Please provide api user credentials.', 401);
}
// check if present // check if present
if (empty($request)) { if (empty($request)) {
throw new Exception('Empty request body.', 400); throw new Exception('Empty request body.', 400);
} }
// decode json request // decode json request
$decoded_request = json_decode($request, true); $decoded_request = json_decode($request, true);
// is it valid? // is it valid?
if (is_null($decoded_request)) { if (is_null($decoded_request)) {
throw new Exception('Invalid JSON Format.', 400); throw new Exception('Invalid JSON Format.', 400);
} }
return self::validateBody($decoded_request); return self::validateBody($decoded_request);
} }
/** /**
* validates the given api credentials * validates the given api credentials
* *
* @param string $key * @param string $key
* @param string $secret * @param string $secret
* @return boolean * @return boolean
*/ */
private static function validateAuth(string $key, string $secret): bool private static function validateAuth(string $key, string $secret): bool
{ {
$sel_stmt = \Froxlor\Database\Database::prepare( $sel_stmt = \Froxlor\Database\Database::prepare(
" "
SELECT ak.*, a.api_allowed as admin_api_allowed, c.api_allowed as cust_api_allowed, c.deactivated SELECT ak.*, a.api_allowed as admin_api_allowed, c.api_allowed as cust_api_allowed, c.deactivated
FROM `api_keys` ak FROM `api_keys` ak
LEFT JOIN `panel_admins` a ON a.adminid = ak.adminid LEFT JOIN `panel_admins` a ON a.adminid = ak.adminid
LEFT JOIN `panel_customers` c ON c.customerid = ak.customerid LEFT JOIN `panel_customers` c ON c.customerid = ak.customerid
WHERE `apikey` = :ak AND `secret` = :as WHERE `apikey` = :ak AND `secret` = :as
" "
); );
$result = \Froxlor\Database\Database::pexecute_first($sel_stmt, array( $result = \Froxlor\Database\Database::pexecute_first($sel_stmt, array(
'ak' => $key, 'ak' => $key,
'as' => $secret 'as' => $secret
), true, true); ), true, true);
if ($result) { if ($result) {
if ($result['apikey'] == $key && $result['secret'] == $secret && ($result['valid_until'] == -1 || $result['valid_until'] >= time( if ($result['apikey'] == $key && $result['secret'] == $secret && ($result['valid_until'] == -1 || $result['valid_until'] >= time()) && (($result['customerid'] == 0 && $result['admin_api_allowed'] == 1) || ($result['customerid'] > 0 && $result['cust_api_allowed'] == 1 && $result['deactivated'] == 0))) {
)) && (($result['customerid'] == 0 && $result['admin_api_allowed'] == 1) || ($result['customerid'] > 0 && $result['cust_api_allowed'] == 1 && $result['deactivated'] == 0))) { // get user to check whether api call is allowed
// get user to check whether api call is allowed if (!empty($result['allowed_from'])) {
if (!empty($result['allowed_from'])) { // @todo allow specification and validating of whole subnets later
// @todo allow specification and validating of whole subnets later $ip_list = explode(",", $result['allowed_from']);
$ip_list = explode(",", $result['allowed_from']); $access_ip = inet_ntop(inet_pton($_SERVER['REMOTE_ADDR']));
$access_ip = inet_ntop(inet_pton($_SERVER['REMOTE_ADDR'])); if (in_array($access_ip, $ip_list)) {
if (in_array($access_ip, $ip_list)) { return true;
return true; }
} } else {
} else { return true;
return true; }
} }
} }
} return false;
return false; }
}
/** /**
* validates the given command * validates the given command
* *
* @param array $request * @param array $request
* *
* @return array * @return array
* @throws Exception * @throws Exception
*/ */
private static function validateBody($request) private static function validateBody($request)
{ {
// check command exists // check command exists
if (empty($request['command'])) { if (empty($request['command'])) {
throw new Exception("Please provide a command.", 400); throw new Exception("Please provide a command.", 400);
} }
$command = explode(".", $request['command']); $command = explode(".", $request['command']);
if (count($command) != 2) { if (count($command) != 2) {
throw new Exception("The given command is invalid.", 400); throw new Exception("The given command is invalid.", 400);
} }
// simply check for file-existance, as we do not want to use our autoloader because this way // simply check for file-existance, as we do not want to use our autoloader because this way
// it will recognize non-api classes+methods as valid commands // it will recognize non-api classes+methods as valid commands
$apiclass = '\\Froxlor\\Api\\Commands\\' . $command[0]; $apiclass = '\\Froxlor\\Api\\Commands\\' . $command[0];
if (!class_exists($apiclass) || !@method_exists($apiclass, $command[1])) { if (!class_exists($apiclass) || !@method_exists($apiclass, $command[1])) {
throw new Exception("Unknown command", 400); throw new Exception("Unknown command", 400);
} }
return array( return array(
'command' => array( 'command' => array(
'class' => $command[0], 'class' => $command[0],
'method' => $command[1] 'method' => $command[1]
), ),
'params' => $request['params'] ?? null 'params' => $request['params'] ?? null
); );
} }
} }

View File

@@ -19,15 +19,13 @@ if (! defined('AREA')) {
* *
*/ */
use Froxlor\Api\Commands\SubDomains as SubDomains; use Froxlor\Api\Commands\SubDomains;
use Froxlor\Settings; use Froxlor\Settings;
use Froxlor\UI\Request; use Froxlor\UI\Request;
// This file is being included in admin_domains and customer_domains // This file is being included in admin_domains and customer_domains
// and therefore does not need to require lib/init.php // and therefore does not need to require lib/init.php
// TODO get domain related settings for logfile (speciallogfile)
$domain_id = (int) Request::get('domain_id'); $domain_id = (int) Request::get('domain_id');
$last_n = (int) Request::get('number_of_lines', 100); $last_n = (int) Request::get('number_of_lines', 100);