diff --git a/composer.json b/composer.json index d509ab0..1254322 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "24unix/bindapi", "description": "manage Bind9 DNS server via REST API", "version": "1.0.9", - "build_number": "357", + "build_number": "358", "authors": [ { "name": "Micha Espey", diff --git a/src/Controller/RequestController.php b/src/Controller/RequestController.php index f7e9dbd..d7fbb1f 100644 --- a/src/Controller/RequestController.php +++ b/src/Controller/RequestController.php @@ -23,7 +23,7 @@ use function Symfony\Component\String\s; /** * */ -#[OAT\Info(version: '0.0.1', title: 'bindAPI')] +#[OAT\Info(version: '1.0.9', title: 'bindAPI')] #[OAT\Server( url: "{schema}://{hostname}/api", description: "The bindAPI URL.", @@ -60,75 +60,69 @@ class RequestController private array $uri; - public function __construct( - private readonly ApikeyRepository $apikeyRepository, - private readonly DomainController $domainController, - private readonly DomainRepository $domainRepository, - private readonly DynDNSRepository $dynDNSRepository, - private readonly PanelRepository $panelRepository, - private readonly ConfigController $configController, - private readonly EncryptionController $encryptionController, - private readonly Logger $logger) + + // server tag + + #[OAT\Get( + path: '/ping', + operationId: 'ping', + description: 'Checks for connectivity and valid APIkey', + security: [ + ['Authorization' => []] + ], + tags: ['Server'], + responses: [ + new OAT\Response( + response: 200, + description: 'OK' + ), + new OAT\Response( + response: 401, + description: 'API key is missing or invalid.' + ) + ] + )] + private function handlePing(): void { - $this->status = ''; - $this->response = ''; - $this->message = ''; - $this->result = []; - } - - public function handleRequest(string $requestMethod, array $uri): void - { - $this->logger->debug(message: "Request: $requestMethod $uri[1]"); - - $this->requestMethod = strtoupper(string: $requestMethod); - $this->uri = $uri; - - $command = $this->uri[2]; - - // use my router class from address book? - $routes = ['domains', 'ping', 'apidoc', 'dyndns']; - - if (empty($command) || !(in_array(needle: $command, haystack: $routes))) { - $this->status = "404 Not Found"; - $this->message = "Endpoint not found."; + if ($this->validateApiKey()) { + $this->status = '200 OK'; + $this->response = 'pong'; } else { - try { - match ($command) { - 'dyndns' => $this->handleDynDNS(), - 'ping' => $this->handlePing(), - 'domains' => $this->handleDomains(), - 'apidoc' => $this->apiDoc(), - }; - } catch (UnhandledMatchError) { - $this->status = '400 Bad Request'; - $this->message = 'Unknown path: ' . $command; - } - } - - // process api requests - if (!empty($this->status)) { - header(header: $_SERVER['SERVER_PROTOCOL'] . ' ' . $this->status); - } - - if (!empty($this->response)) { - echo json_encode(value: [ - 'response' => $this->response - ]); - } elseif (!empty($this->result)) { - echo json_encode(value: [ - 'result' => $this->result - ]); - } elseif (!empty($this->message)) { - echo json_encode(value: [ - 'message' => $this->message - ]); - } else { - echo json_encode(value: [ - 'message' => $this->message ?? 'Error: No message.' - ]); + $this->status = '401 Unauthorized'; + $this->message = 'API key is missing or invalid'; } } + #[OAT\Get( + path: '/version', + operationId: 'version', + description: 'Check the API version of the nameserver.', + security: [ + ['Authorization' => []] + ], + tags: ['Server'], + responses: [ + new OAT\Response( + response: 200, + description: 'x.y.y' + ), + new OAT\Response( + response: 401, + description: 'API key is missing or invalid.' + ) + ] + )] + + private function getVersion(): void + { + if ($this->validateApiKey()) { + $this->status = '200 OK'; + $this->response = '1.2.3'; + } else { + $this->status = '401 Unauthorized'; + $this->message = 'API key is missing or invalid'; + } + } #[OAT\Get( path: '/domains', @@ -170,16 +164,6 @@ class RequestController /** */ - private function handlePing(): void - { - if ($this->checkPassword()) { - $this->status = '200 OK'; - $this->response = 'pong'; - } else { - $this->status = '401 Unauthorized'; - $this->message = 'API key is missing or invalid'; - } - } /** @@ -187,7 +171,7 @@ class RequestController */ private function handleDomains(): void { - if ($this->checkPassword()) { + if ($this->validateApiKey()) { try { match ($this->requestMethod) { 'GET' => $this->handleDomainsGetRequest(), @@ -275,9 +259,7 @@ class RequestController )] )] - - - private function checkPassword(): bool + private function validateApiKey(): bool { $headers = array_change_key_case(array: getallheaders(), case: CASE_UPPER); $apiKey = $headers['X-API-KEY'] ?? ''; @@ -459,7 +441,7 @@ class RequestController { $this->logger->debug(message: 'handleDynDNS()'); - if ($this->checkPassword()) { + if ($this->validateApiKey()) { $host = $this->uri[3] ?? ''; if (empty($host)) { @@ -665,5 +647,76 @@ class RequestController exit(0); } + public function __construct( + private readonly ApikeyRepository $apikeyRepository, + private readonly DomainController $domainController, + private readonly DomainRepository $domainRepository, + private readonly DynDNSRepository $dynDNSRepository, + private readonly PanelRepository $panelRepository, + private readonly ConfigController $configController, + private readonly EncryptionController $encryptionController, + private readonly Logger $logger) + { + $this->status = ''; + $this->response = ''; + $this->message = ''; + $this->result = []; + } + + public function handleRequest(string $requestMethod, array $uri): void + { + $this->logger->debug(message: "Request: $requestMethod $uri[1]"); + + $this->requestMethod = strtoupper(string: $requestMethod); + $this->uri = $uri; + + $command = $this->uri[2]; + + // use my router class from address book? + $routes = ['domains', 'ping', 'apidoc', 'dyndns']; + + if (empty($command) || !(in_array(needle: $command, haystack: $routes))) { + $this->status = "404 Not Found"; + $this->message = "Endpoint not found."; + } else { + try { + match ($command) { + // server + 'ping' => $this->handlePing(), + 'version' => $this->getVersion(), + // domains + 'domains' => $this->handleDomains(), + 'dyndns' => $this->handleDynDNS(), + 'apidoc' => $this->apiDoc(), + }; + } catch (UnhandledMatchError) { + $this->status = '400 Bad Request'; + $this->message = 'Unknown path: ' . $command; + } + } + + // process api requests + if (!empty($this->status)) { + header(header: $_SERVER['SERVER_PROTOCOL'] . ' ' . $this->status); + } + + if (!empty($this->response)) { + echo json_encode(value: [ + 'response' => $this->response + ]); + } elseif (!empty($this->result)) { + echo json_encode(value: [ + 'result' => $this->result + ]); + } elseif (!empty($this->message)) { + echo json_encode(value: [ + 'message' => $this->message + ]); + } else { + echo json_encode(value: [ + 'message' => $this->message ?? 'Error: No message.' + ]); + } + } }