Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file.
Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles.

## [Unreleased][unreleased]
### Changed
* Code refactored to support PHP 7.1 to 8.4

## 3.1.0

Expand Down
3 changes: 0 additions & 3 deletions src/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ class Api
private $rateLimit;

/**
* @param EndpointInterface $endpoint
* @param ApiHandlerInterface|string $handler
* @param ApiAuthorizationInterface $authorization
* @param RateLimitInterface|null $rateLimit
*/
public function __construct(
EndpointInterface $endpoint,
Expand Down
14 changes: 6 additions & 8 deletions src/ApiDecider.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ public function __construct(Container $container)
* Get api handler that match input method, version, package and apiAction.
* If decider cannot find handler for given handler, returns defaults.
*
* @param string $method
* @param string $version
* @param string $package
* @param string $apiAction
*
* @return Api
Expand All @@ -54,31 +51,31 @@ public function getApi(string $method, string $version, string $package, ?string
$handler->setEndpointIdentifier($endpointIdentifier);
return new Api($api->getEndpoint(), $handler, $api->getAuthorization(), $api->getRateLimit());
}

if ($method === 'OPTIONS' && $this->globalPreflightHandler && $identifier->getVersion() === $version && $identifier->getPackage() === $package && $identifier->getApiAction() === $apiAction) {
return new Api(new EndpointIdentifier('OPTIONS', $version, $package, $apiAction), $this->globalPreflightHandler, new NoAuthorization());
}
}

return new Api(new EndpointIdentifier($method, $version, $package, $apiAction), new DefaultHandler(), new NoAuthorization());
}

public function enableGlobalPreflight(CorsPreflightHandlerInterface $corsHandler = null)
public function enableGlobalPreflight(?CorsPreflightHandlerInterface $corsHandler = null)
{
if (!$corsHandler) {
$corsHandler = new CorsPreflightHandler(new Response());
}

$this->globalPreflightHandler = $corsHandler;
}

/**
* Register new api handler
*
* @param EndpointInterface $endpointIdentifier
* @param ApiHandlerInterface|string $handler
* @param ApiAuthorizationInterface $apiAuthorization
* @param RateLimitInterface|null $rateLimit
* @return self
*/
public function addApi(EndpointInterface $endpointIdentifier, $handler, ApiAuthorizationInterface $apiAuthorization, RateLimitInterface $rateLimit = null): self
public function addApi(EndpointInterface $endpointIdentifier, $handler, ApiAuthorizationInterface $apiAuthorization, ?RateLimitInterface $rateLimit = null): self
{
$this->apis[] = new Api($endpointIdentifier, $handler, $apiAuthorization, $rateLimit);
return $this;
Expand All @@ -96,6 +93,7 @@ public function getApis(): array
$handler = $this->getHandler($api);
$apis[] = new Api($api->getEndpoint(), $handler, $api->getAuthorization(), $api->getRateLimit());
}

return $apis;
}

Expand Down
4 changes: 0 additions & 4 deletions src/Authorization/ApiAuthorizationInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,12 @@ interface ApiAuthorizationInterface
{
/**
* Main method to check if this authorization authorize actual request.
*
* @return boolean
*/
public function authorized(): bool;

/**
* If authorization deny acces, this method should provide additional information
* abount cause of restriction.
*
* @return string|null
*/
public function getErrorMessage(): ?string;
}
2 changes: 1 addition & 1 deletion src/Authorization/BasicAuthentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class BasicAuthentication implements ApiAuthorizationInterface

/**
* @param array<string, string> $autentications - available username - password pairs
* @param IRequest $httpRequest
*/
public function __construct(array $autentications, IRequest $httpRequest)
{
Expand All @@ -34,6 +33,7 @@ public function authorized(): bool
if (!$authentication) {
return false;
}

return $authentication === $urlScript->getPassword();
}

Expand Down
8 changes: 3 additions & 5 deletions src/Authorization/BearerTokenAuthorization.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ class BearerTokenAuthorization extends TokenAuthorization
{
/**
* BearerTokenAuthorization constructor.
*
* @param TokenRepositoryInterface $tokenRepository
* @param IpDetectorInterface $ipDetector
*/
public function __construct(TokenRepositoryInterface $tokenRepository, IpDetectorInterface $ipDetector)
{
Expand All @@ -23,24 +20,25 @@ public function __construct(TokenRepositoryInterface $tokenRepository, IpDetecto
/**
* Read HTTP reader with authorization token
* If everything is ok, it return token. In other situations returns false and set errorMessage.
*
* @return string|null
*/
protected function readAuthorizationToken(): ?string
{
if (!isset($_SERVER['HTTP_AUTHORIZATION'])) {
$this->errorMessage = 'Authorization header HTTP_Authorization is not set';
return null;
}

$parts = explode(' ', $_SERVER['HTTP_AUTHORIZATION']);
if (count($parts) !== 2) {
$this->errorMessage = 'Authorization header contains invalid structure';
return null;
}

if (strtolower($parts[0]) !== 'bearer') {
$this->errorMessage = 'Authorization header doesn\'t contain bearer token';
return null;
}

return $parts[1];
}
}
1 change: 1 addition & 0 deletions src/Authorization/CookieApiKeyAuthentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ protected function readAuthorizationToken(): ?string
$this->errorMessage = 'API key is not set';
return null;
}

return $apiKey;
}

Expand Down
1 change: 1 addition & 0 deletions src/Authorization/HeaderApiKeyAuthentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ protected function readAuthorizationToken(): ?string
$this->errorMessage = 'API key is not set';
return null;
}

return $apiKey;
}

Expand Down
1 change: 1 addition & 0 deletions src/Authorization/QueryApiKeyAuthentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ protected function readAuthorizationToken(): ?string
$this->errorMessage = 'API key is not set';
return null;
}

return $apiKey;
}

Expand Down
14 changes: 5 additions & 9 deletions src/Authorization/TokenAuthorization.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ abstract class TokenAuthorization implements ApiAuthorizationInterface
*/
protected $ipDetector;

/**
* @param TokenRepositoryInterface $tokenRepository
* @param IpDetectorInterface $ipDetector
*/
public function __construct(TokenRepositoryInterface $tokenRepository, IpDetectorInterface $ipDetector)
{
$this->tokenRepository = $tokenRepository;
Expand Down Expand Up @@ -74,17 +70,17 @@ public function getErrorMessage(): ?string
* '127.0.0.1,127.0.02' - accessible from multiple IP, separator could be new line or space
* '127.0.0.1/32' - accessible from ip range
* null - disabled access
*
* @return boolean
*/
private function isValidIp(?string $ipRestrictions): bool
{
if ($ipRestrictions === null) {
return false;
}

if ($ipRestrictions === '*' || $ipRestrictions === '') {
return true;
}

$ip = $this->ipDetector->getRequestIp();

$ipWhiteList = str_replace([',', ' ', "\n"], '#', $ipRestrictions);
Expand All @@ -93,6 +89,7 @@ private function isValidIp(?string $ipRestrictions): bool
if ($whiteIp === $ip) {
return true;
}

if (strpos($whiteIp, '/') !== false) {
return $this->ipInRange($ip, $whiteIp);
}
Expand All @@ -106,14 +103,13 @@ private function isValidIp(?string $ipRestrictions): bool
*
* @param string $ip this ip will be verified
* @param string $range is in IP/CIDR format eg 127.0.0.1/24
* @return boolean
*/
private function ipInRange(string $ip, string $range): bool
{
list($range, $netmask) = explode('/', $range, 2);
[$range, $netmask] = explode('/', $range, 2);
$range_decimal = ip2long($range);
$ipDecimal = ip2long($ip);
$wildcard_decimal = pow(2, (32 - (int)$netmask)) - 1;
$wildcard_decimal = 2 ** (32 - (int)$netmask) - 1;
$netmask_decimal = ~ $wildcard_decimal;
return (($ipDecimal & $netmask_decimal) === ($range_decimal & $netmask_decimal));
}
Expand Down
6 changes: 4 additions & 2 deletions src/Component/ApiConsoleControl.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ApiConsoleControl extends Control

private $templateFilePath;

public function __construct(IRequest $request, EndpointInterface $endpoint, ApiHandlerInterface $handler, ApiAuthorizationInterface $authorization, ApiLink $apiLink = null, ApiConsoleFormFactoryInterface $formFactory = null)
public function __construct(IRequest $request, EndpointInterface $endpoint, ApiHandlerInterface $handler, ApiAuthorizationInterface $authorization, ?ApiLink $apiLink = null, ?ApiConsoleFormFactoryInterface $formFactory = null)
{
$this->request = $request;
$this->endpoint = $endpoint;
Expand All @@ -63,7 +63,7 @@ protected function createComponentConsoleForm(): Form
{
$form = $this->formFactory->create($this->request, $this->endpoint, $this->handler, $this->authorization, $this->apiLink);
$form->setRenderer($this->getFormRenderer());
$form->onSuccess[] = array($this, 'formSucceeded');
$form->onSuccess[] = [$this, 'formSucceeded'];
return $form;
}

Expand Down Expand Up @@ -142,8 +142,10 @@ private function filterFormValues(array $values): array
if ($values['do_not_send_empty_value_for_' . $key] === true && $values[$key] === '') {
unset($values[$key]);
}

unset($values['do_not_send_empty_value_for_' . $key]);
}

return $values;
}
}
3 changes: 2 additions & 1 deletion src/Component/ApiListingControl.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public function handleSelect(string $method, $version, string $package, ?string

/**
* @param Api[] $handlers
* @return array
*/
private function groupApis(array $handlers): array
{
Expand All @@ -54,8 +53,10 @@ private function groupApis(array $handlers): array
if (!isset($versionHandlers[$endPoint->getVersion()])) {
$versionHandlers[$endPoint->getVersion()] = [];
}

$versionHandlers[$endPoint->getVersion()][] = $handler;
}

return $versionHandlers;
}

Expand Down
1 change: 1 addition & 0 deletions src/Component/DefaultApiConsoleFormFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ protected function getUrl(IRequest $request, EndpointInterface $endpoint, ?ApiLi
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
$scheme = $_SERVER['HTTP_X_FORWARDED_PROTO'];
}

$port = '';
if ($uri->scheme === 'http' && $uri->port !== 80) {
$port = ':' . $uri->port;
Expand Down
4 changes: 3 additions & 1 deletion src/EndpointIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public function __construct(string $method, $version, string $package, ?string $
if (strpos($version, '/') !== false) {
throw new InvalidArgumentException('Version must have semantic numbering. For example "1", "1.1", "0.13.2" etc.');
}

$this->version = $version;
$this->package = $package;
$this->apiAction = $apiAction;
Expand All @@ -54,11 +55,12 @@ public function getApiAction(): ?string
if ($this->apiAction === '') {
return null;
}

return $this->apiAction;
}

public function getUrl(): string
{
return "v{$this->version}/{$this->package}/{$this->apiAction}";
return sprintf('v%s/%s/%s', $this->version, $this->package, $this->apiAction);
}
}
21 changes: 9 additions & 12 deletions src/Error/DefaultErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,30 @@ public function handle(Throwable $exception, array $params): JsonApiResponse
{
Debugger::log($exception, Debugger::EXCEPTION);
if ($this->outputConfigurator->showErrorDetail()) {
$response = new JsonApiResponse(Response::S500_INTERNAL_SERVER_ERROR, ['status' => 'error', 'message' => 'Internal server error', 'detail' => $exception->getMessage()]);
} else {
$response = new JsonApiResponse(Response::S500_INTERNAL_SERVER_ERROR, ['status' => 'error', 'message' => 'Internal server error']);
return new JsonApiResponse(Response::S500_INTERNAL_SERVER_ERROR, ['status' => 'error', 'message' => 'Internal server error', 'detail' => $exception->getMessage()]);
}
return $response;

return new JsonApiResponse(Response::S500_INTERNAL_SERVER_ERROR, ['status' => 'error', 'message' => 'Internal server error']);
}

public function handleInputParams(array $errors): JsonApiResponse
{
if ($this->outputConfigurator->showErrorDetail()) {
$response = new JsonApiResponse(Response::S400_BAD_REQUEST, ['status' => 'error', 'message' => 'wrong input', 'detail' => $errors]);
} else {
$response = new JsonApiResponse(Response::S400_BAD_REQUEST, ['status' => 'error', 'message' => 'wrong input']);
return new JsonApiResponse(Response::S400_BAD_REQUEST, ['status' => 'error', 'message' => 'wrong input', 'detail' => $errors]);
}
return $response;

return new JsonApiResponse(Response::S400_BAD_REQUEST, ['status' => 'error', 'message' => 'wrong input']);
}

public function handleSchema(array $errors, array $params): JsonApiResponse
{
Debugger::log($errors, Debugger::ERROR);

if ($this->outputConfigurator->showErrorDetail()) {
$response = new JsonApiResponse(Response::S500_INTERNAL_SERVER_ERROR, ['status' => 'error', 'message' => 'Internal server error', 'detail' => $errors]);
} else {
$response = new JsonApiResponse(Response::S500_INTERNAL_SERVER_ERROR, ['status' => 'error', 'message' => 'Internal server error']);
return new JsonApiResponse(Response::S500_INTERNAL_SERVER_ERROR, ['status' => 'error', 'message' => 'Internal server error', 'detail' => $errors]);
}
return $response;

return new JsonApiResponse(Response::S500_INTERNAL_SERVER_ERROR, ['status' => 'error', 'message' => 'Internal server error']);
}

public function handleAuthorization(ApiAuthorizationInterface $auth, array $params): JsonApiResponse
Expand Down
8 changes: 0 additions & 8 deletions src/Handlers/ApiHandlerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ interface ApiHandlerInterface
{
/**
* Summary of handler - short description of handler
* @return string
*/
public function summary(): string;

/**
* Description of handler
* @return string
*/
public function description(): string;

Expand All @@ -32,33 +30,27 @@ public function params(): array;

/**
* Returns list of tags for handler
* @return array
*/
public function tags(): array;

/**
* Marks handler as deprecated
* @return bool
*/
public function deprecated(): bool;

/**
* Main handle method that will be executed when api
* endpoint contected with this handler will be triggered
*
* @param array $params
*
* @return ResponseInterface
*/
public function handle(array $params): ResponseInterface;

/**
* Set actual endpoint identifier to hnadler.
* It is neccesary for link creation.
*
* @param EndpointInterface $endpoint
*
* @return void
*/
public function setEndpointIdentifier(EndpointInterface $endpoint): void;

Expand Down
Loading