diff --git a/src/Controller/RequestController.php b/src/Controller/RequestController.php index 28c52c2..32d92ad 100644 --- a/src/Controller/RequestController.php +++ b/src/Controller/RequestController.php @@ -22,640 +22,647 @@ use UnhandledMatchError; */ #[OAT\Info(version: '0.0.1', title: 'bindAPI')] #[OAT\Server( - url : "{schema}://{hostname}/api", - description: "The bindAPI URL.", - variables : [ - new OAT\ServerVariable( - serverVariable: "schema", - default : "https", - enum : ["https", "http"] - ), - new OAT\ServerVariable( - serverVariable: "hostname", - default : "ns2.24unix.net", - ) - ] + url: "{schema}://{hostname}/api", + description: "The bindAPI URL.", + variables: [ + new OAT\ServerVariable( + serverVariable: "schema", + default: "https", + enum: ["https", "http"] + ), + new OAT\ServerVariable( + serverVariable: "hostname", + default: "ns2.24unix.net", + ) + ] )] #[OAT\Tag( - name: "Server" + name: "Server" )] #[OAT\SecurityScheme( - securityScheme: "Authorization", - type : "apiKey", - description : "description", - name : "X-API-Key", - in : "header" + securityScheme: "Authorization", + type: "apiKey", + description: "description", + name: "X-API-Key", + in: "header" )] class RequestController { - private string $status; - private string $response; - private string $message; - private array $result; - private string $requestMethod; - private array $uri; - - - /** - * @param ApiController $apiController - * @param ApikeyRepository $apikeyRepository - * @param DomainController $domainController - * @param DomainRepository $domainRepository - * @param DynDNSRepository $dynDNSRepository - * @param PanelRepository $panelRepository - * @param Logger $logger - */ - public function __construct( - private readonly ApiController $apiController, - private readonly ApikeyRepository $apikeyRepository, - private readonly DomainController $domainController, - private readonly DomainRepository $domainRepository, - private readonly DynDNSRepository $dynDNSRepository, - private readonly PanelRepository $panelRepository, - private readonly Logger $logger) - { - $this->status = ''; - $this->response = ''; - $this->message = ''; - $this->result = []; - } - - /** - * @return void - */ - #[OAT\Get( - path : '/domains', - operationId: 'getAllDomains', - description: 'Returns a list of all domains on this server.', - summary : 'Listing all domains.', + private string $status; + private string $response; + private string $message; + private array $result; + private string $requestMethod; + private array $uri; + + + /** + * @param ApiController $apiController + * @param ApikeyRepository $apikeyRepository + * @param DomainController $domainController + * @param DomainRepository $domainRepository + * @param DynDNSRepository $dynDNSRepository + * @param PanelRepository $panelRepository + * @param ConfigController $configController + * @param EncryptionController $encryptionController + * @param Logger $logger + */ + public function __construct( + private readonly ApiController $apiController, + 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 = []; + } + + /** + * @return void + */ + #[OAT\Get( + path: '/domains', + operationId: 'getAllDomains', + description: 'Returns a list of all domains on this server.', + summary: 'Listing all domains.', // security: [ // 'Authorization' => [ // // "read:api" // ] // ], - servers : [], - tags : ['Domains'], - responses : [ - new OAT\Response( - response : 200, - description: 'OK' - ), - new OAT\Response( - response : 401, - description: 'API key is missing or invalid.' - ), - new OAT\Response( - response : 404, - description: 'Domain not found.' - )] - )] - private function handleAllDomainsGetRequest(): void - { - $domains = $this->domainRepository->findAll(); - $resultDomain = []; - foreach ($domains as $singleDomain) { - $domain = [ - 'id' => $singleDomain->getId(), - 'name' => $singleDomain->getName(), - 'panel' => $singleDomain->getPanel() - ]; - $resultDomain[] = $domain; - } - $this->result = $resultDomain; - } - - /** - */ - 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'; - } - } - - - /** - * @return void - */ - private function handleDomains(): void - { - if ($this->checkPassword()) { - try { - match ($this->requestMethod) { - 'GET' => $this->handleDomainsGetRequest(), - 'POST' => $this->handleDomainsPostRequest(), - 'PUT' => $this->handleDomainsPutRequest(), - 'DELETE' => $this->handleDomainsDeleteRequest() - }; - } catch (UnhandledMatchError) { - $this->status = '400 Bad Request'; - $this->message = "unknown request method: $this->requestMethod"; - } - } - } - - - /** - * @OA\Tag(name = "Server") - * @OA\Get( - * path = "/ping", - * summary = "Returning pong.", - * description = "Can be used to check API or server availability.", - * tags={"Server"}, - * @OA\Response(response = "200", description = "OK"), - * @OA\Response(response = "401", description = "API key is missing or invalid."), - * security={ - * {"Authorization":{"read"}} - * } - * ) - * - * @OA\Tag(name = "Domains") - * @OA\Put( - * path="/domains/{name}", - * summary="Updates a domain.", - * description="Updates a domain. Only supplied fields will be updated, existing won't be affected.", - * tags={"Domains"}, - * @OA\Response(response="200", description="OK"), - * @OA\Response(response = "401", description = "API key is missing or invalid."), - * @OA\Response(response="404", description="Domain not found."), - * security={ - * {"Authorization":{"read":"write"}} - * } - * ) - * @OA\Delete ( - * path="/domains/{name}", - * summary="Deletes a domain.", - * description="Deletes a domain.", - * tags={"Domains"}, - * @OA\Response(response="200", description="OK"), - * @OA\Response(response = "401", description = "API key is missing or invalid."), - * @OA\Response(response="404", description="Domain not found."), - * security={ - * {"Authorization":{"read":"write"}} - * } - * ) - * @param string $requestMethod - * @param array $uri - * - * @return void - */ - - #[ - OAT\Get( - path : '/domains/{name}', - operationId: 'getSingleDomain', - description: 'Returns information of a single domain specified by its domain name.', - summary : 'Returns a single domain.', - security : [ - ], - tags : ['Domains'], - parameters : [ - new OAT\Parameter(name: 'name', in: 'path', required: true, schema: new OAT\Schema(type: 'string')), - ], - responses : [ - new OAT\Response( - response : 200, - description: 'OK' - ), - new OAT\Response( - response : 401, - description: 'API key is missing or invalid.' - ), - new OAT\Response( - response : 404, - description: 'Domain not found.' - )] - - )] - 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]; - - if (empty($command) || !(($command == 'domains') || ($command == 'ping') || ($command == 'apidoc') || ($command == 'dyndns'))) { - $this->status = "404 Not Found"; - $this->message = "Endpoint not found."; - } else { - try { - match ($command) { - 'dyndns' => $this->handleDynDNS(), - 'ping' => $this->handlePing(), - 'domains' => $this->handleDomains(), - }; - } catch (UnhandledMatchError) { - $this->status = '400 Bad Request'; - $this->message = 'Unknown path: ' . $command; - } - } - - 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.' - ]); - } - } - - - /** - * @return bool - */ - private function checkPassword(): bool - { - $headers = array_change_key_case(array: getallheaders(), case: CASE_UPPER); - $apiKey = $headers['X-API-KEY'] ?? ''; + servers: [], + tags: ['Domains'], + responses: [ + new OAT\Response( + response: 200, + description: 'OK' + ), + new OAT\Response( + response: 401, + description: 'API key is missing or invalid.' + ), + new OAT\Response( + response: 404, + description: 'Domain not found.' + )] + )] + private function handleAllDomainsGetRequest(): void + { + $domains = $this->domainRepository->findAll(); + $resultDomain = []; + foreach ($domains as $singleDomain) { + $domain = [ + 'id' => $singleDomain->getId(), + 'name' => $singleDomain->getName(), + 'panel' => $singleDomain->getPanel() + ]; + $resultDomain[] = $domain; + } + $this->result = $resultDomain; + } + + /** + */ + 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'; + } + } + + + /** + * @return void + */ + private function handleDomains(): void + { + if ($this->checkPassword()) { + try { + match ($this->requestMethod) { + 'GET' => $this->handleDomainsGetRequest(), + 'POST' => $this->handleDomainsPostRequest(), + 'PUT' => $this->handleDomainsPutRequest(), + 'DELETE' => $this->handleDomainsDeleteRequest() + }; + } catch (UnhandledMatchError) { + $this->status = '400 Bad Request'; + $this->message = "unknown request method: $this->requestMethod"; + } + } + } + + + /** + * @OA\Tag(name = "Server") + * @OA\Get( + * path = "/ping", + * summary = "Returning pong.", + * description = "Can be used to check API or server availability.", + * tags={"Server"}, + * @OA\Response(response = "200", description = "OK"), + * @OA\Response(response = "401", description = "API key is missing or invalid."), + * security={ + * {"Authorization":{"read"}} + * } + * ) + * + * @OA\Tag(name = "Domains") + * @OA\Put( + * path="/domains/{name}", + * summary="Updates a domain.", + * description="Updates a domain. Only supplied fields will be updated, existing won't be affected.", + * tags={"Domains"}, + * @OA\Response(response="200", description="OK"), + * @OA\Response(response = "401", description = "API key is missing or invalid."), + * @OA\Response(response="404", description="Domain not found."), + * security={ + * {"Authorization":{"read":"write"}} + * } + * ) + * @OA\Delete ( + * path="/domains/{name}", + * summary="Deletes a domain.", + * description="Deletes a domain.", + * tags={"Domains"}, + * @OA\Response(response="200", description="OK"), + * @OA\Response(response = "401", description = "API key is missing or invalid."), + * @OA\Response(response="404", description="Domain not found."), + * security={ + * {"Authorization":{"read":"write"}} + * } + * ) + * @param string $requestMethod + * @param array $uri + * + * @return void + */ + + #[ + OAT\Get( + path: '/domains/{name}', + operationId: 'getSingleDomain', + description: 'Returns information of a single domain specified by its domain name.', + summary: 'Returns a single domain.', + security: [ + ], + tags: ['Domains'], + parameters: [ + new OAT\Parameter(name: 'name', in: 'path', required: true, schema: new OAT\Schema(type: 'string')), + ], + responses: [ + new OAT\Response( + response: 200, + description: 'OK' + ), + new OAT\Response( + response: 401, + description: 'API key is missing or invalid.' + ), + new OAT\Response( + response: 404, + description: 'Domain not found.' + )] + + )] + 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]; + + if (empty($command) || !(($command == 'domains') || ($command == 'ping') || ($command == 'apidoc') || ($command == 'dyndns'))) { + $this->status = "404 Not Found"; + $this->message = "Endpoint not found."; + } else { + try { + match ($command) { + 'dyndns' => $this->handleDynDNS(), + 'ping' => $this->handlePing(), + 'domains' => $this->handleDomains(), + }; + } catch (UnhandledMatchError) { + $this->status = '400 Bad Request'; + $this->message = 'Unknown path: ' . $command; + } + } + + 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.' + ]); + } + } + + + /** + * @return bool + */ + private function checkPassword(): bool + { + $headers = array_change_key_case(array: getallheaders(), case: CASE_UPPER); + $apiKey = $headers['X-API-KEY'] ?? ''; + + if (empty($apiKey)) { + $this->status = "401 Unauthorized"; + $this->message = "API key is missing."; + return false; + } else { + [$prefix,] = explode(separator: '.', string: $apiKey); + if ($apiResult = $this->apikeyRepository->findByPrefix(prefix: $prefix)) { + $encryptedHash = $apiResult->getApikey(); + $encryptionKey = $this->configController->getConfig(configKey: 'encryptionKey'); + $decryptedHash = $this->encryptionController->safeDecrypt(encrypted: $encryptedHash, key: $encryptionKey); + + if (!password_verify(password: $apiKey, hash: $decryptedHash)) { + $this->status = "401 Unauthorized"; + $this->message = "API key mismatch."; + return false; + } + } else { + $this->status = "401 Unauthorized"; + $this->message = "Invalid API key."; + return false; + } + } + return true; + } + + + /** + * @return void + */ + private function handleDomainsGetRequest(): void + { + $name = $this->uri[3] ?? ''; + + if ($name == 'name') { + if ($result = $this->domainRepository->findByName(name: $this->uri[4])) { + $domain = [ + 'id' => $result->getId(), + 'name' => $result->getName(), + 'panel' => $result->getPanel() + ]; + $this->result = $domain; + } else { + $this->status = "404 Not Found "; + $this->message = "The specified domain was not found."; + } + } else { + if (empty($name)) { + $this->handleAllDomainsGetRequest(); + } else { + $id = intval(value: $name); + if ($id > 0) { + if ($result = $this->domainRepository->findById(id: $id)) { + $domain = [ + 'id' => $result->getId(), + 'name' => $result->getName(), + 'panel' => $result->getPanel() + ]; + $this->result = $domain; + } else { + $this->status = "404 Not Found "; + $this->message = "The specified domain was not found."; + } + } else { + $this->status = "400 Bad Request"; + $this->message = "You need to supply an ID or user the /domain/name/ path."; + + } + } + } + } + + + /** + * @return void + */ + private function handleDomainsPostRequest(): void + { + $name = $_POST['name'] ?? ''; + $panel = $_POST['panel'] ?? ''; + if (empty($name)) { + $this->status = "400 Bad Request"; + $this->message = "A name is required"; + } else { + if (empty($panel)) { + $this->status = "400 Bad Request"; + $this->message = "A panel ID is required."; + } else { + if ($this->domainRepository->findByName(name: $name)) { + $this->status = "400 Bad request"; + $this->message = "Domain: $name already exists."; + } else { + $domain = new Domain(name: $name, panel: $panel); + if ($result = $this->domainRepository->insert(domain: $domain)) { + $this->status = "201 Created"; + $this->domainController->createSlaveZoneFile(domain: $domain); + } else { + $this->status = "500 Server error"; + } + $this->message = $result; + } + } + } + } + + + /** + * @return void + */ + private function handleDomainsPutRequest(): void + { + $putData = fopen(filename: 'php://input', mode: 'r'); + $data = fread(stream: $putData, length: 8192); + $params = explode(separator: '&', string: $data); + + foreach ($params as $param) { + [$key, $value] = explode(separator: '=', string: $param); + $put[$key] = $value; + } + $id = $put['id'] ?? 0; + $name = $put['name'] ?? ''; + $panel = $put['panel'] ?? ""; + + if ($id == 0) { + $this->status = "400 Bad Request"; + $this->message = "An ID is required"; + } else { + if (!$this->domainRepository->findByID(id: $id)) { + $this->status = "404 Not Found"; + $this->message = "Domain with ID : $id doesn't exist."; + } else { + $domain = new Domain(name: $name, panel: $panel, id: $id); + $this->domainRepository->update(domain: $domain); + $this->status = "201 Updated"; + $this->message = "201 Updated"; + $this->domainController->createSlaveZoneFile(domain: $domain); + } + } + } + + + /** + * @return void + */ + private function handleDomainsDeleteRequest(): void + { + $deleteData = fopen(filename: 'php://input', mode: 'r'); + $data = fread(stream: $deleteData, length: 512); + $params = explode(separator: '&', string: $data); + + foreach ($params as $param) { + [$key, $value] = explode(separator: '=', string: $param); + $delete[$key] = $value; + } + + $id = $delete['id'] ?? 0; + + if ($id == 0) { + $this->status = "400 Bad Request"; + $this->message = "You need to supply an ID."; + } else { + + if (!$domain = $this->domainRepository->findByID(id: $id)) { + $this->status = "400 Bad Request"; + $this->message = "There is no domain with ID $id."; + } else { + $this->domainRepository->delete(domain: $domain); + $this->status = "204 No content."; + $this->message = "The domain $id has been deleted."; + } + } + } + + + private function handleDynDNS(): void + { + $this->logger->debug(message: 'handleDynDNS()'); + + if ($this->checkPassword()) { + $host = $this->uri[3] ?? ''; + + if (empty($host)) { + $this->status = '400 Bad Request'; + } else { + $a = $_POST['a'] ?? ''; + $aaaa = $_POST['aaaa'] ?? ''; + + if (empty($a) && empty($aaaa)) { + $address = $_SERVER['REMOTE_ADDR']; + + if (filter_var(value: $address, filter: FILTER_VALIDATE_IP, options: FILTER_FLAG_IPV6)) { + $aaaa = $address; + } else { + $a = $address; + } + } + + $this->logger->debug(message: 'a: ' . $a); + $this->logger->debug(message: 'aaaa: ' . $aaaa); + + + $domainName = $this->getDomain(host: $host); + $hostName = str_replace(search: '.' . $domainName, replace: '', subject: $host); + if (!$domain = $this->domainRepository->findByName(name: $domainName)) { + $this->status = '404 Not Found'; + $this->message = 'Domain ' . $domainName . ' not found'; + } else { + // check if address has changed + if ($dynDNS = $this->dynDNSRepository->findByName(name: $host)) { + $this->logger->debug(message: 'found host: ' . $host); + $this->logger->debug(message: "a: $a"); + $this->logger->debug(message: "aaaa: $aaaa"); + + $ipChanged = false; + + if (!empty($a)) { + if ($a != $dynDNS->getA()) { + $this->logger->debug(message: $a . ' != ' . $dynDNS->getA()); + $dynDNS->setA(a: $a); + $ipChanged = true; + } + } + + if (!empty($aaaa)) { + if ($aaaa != $dynDNS->getAaaa()) { + $this->logger->debug(message: $aaaa . ' != ' . $dynDNS->getAaaa()); + $dynDNS->setAaaa(aaaa: $aaaa); + $ipChanged = true; + } + } + + if ($ipChanged) { + $this->dynDNSRepository->update(dynDNS: $dynDNS); + } + } else { + $dynDNS = new DynDNS(name: $host, a: $a, aaaa: $aaaa); + $this->dynDNSRepository->insert(dynDNS: $dynDNS); + $ipChanged = true; + } + + + if ($ipChanged) { + $panel = $this->panelRepository->findByName(name: $domain->getPanel()); + + if (!empty($panel->getAaaa())) { + $domainData = $this->apiController->sendCommand( + requestType: 'GET', + serverName: $panel->getName(), + versionIP: 6, + apiKey: $panel->getApikey(), + command: 'domains/name/' . $domainName, + serverType: 'panel'); + } else { + $domainData = $this->apiController->sendCommand( + requestType: 'GET', + serverName: $panel->getName(), + versionIP: 4, + apiKey: $panel->getApikey(), + command: 'domains/name/' . $domainName, + serverType: 'panel'); + } + + $domainDecodedData = json_decode(json: $domainData['data']); + $domainID = $domainDecodedData->id; + + if (!empty($panel->getAaaa())) { + $dnsData = $this->apiController->sendCommand( + requestType: 'GET', + serverName: $panel->getName(), + versionIP: 6, + apiKey: $panel->getApikey(), + command: 'dns/' . $domainID, + serverType: 'panel'); + } else { + $dnsData = $this->apiController->sendCommand( + requestType: 'GET', + serverName: $panel->getName(), + versionIP: 4, + apiKey: $panel->getApikey(), + command: 'dns/' . $domainID, + serverType: 'panel'); + } + + $dnsDataDecoded = json_decode(json: $dnsData['data']); + $soa = $dnsDataDecoded->records->soa; + $others = $dnsDataDecoded->records->other; + + $hostFound = false; + + $updateHost = function (object $host) use ($hostName, $a, $aaaa, &$hostFound) { + if ($host->host == $hostName) { + $hostFound = true; + if ($host->type == 'A') { + if (!empty($a)) { + $host->value = $a; + } + } else { + if (!empty($aaaa)) { + $host->value = $aaaa; + } + } + } + }; + + array_map(callback: $updateHost, array: $others); + + if ($hostFound) { + $newDnsData = json_encode(value: [ + 'records' => [ + 'soa' => $soa, + 'other' => $others + ] + ]); + + if (!empty($panel->getAaaa())) { + $result = $this->apiController->sendCommand( + requestType: 'PUT', + serverName: $panel->getName(), + versionIP: 6, + apiKey: $panel->getApikey(), + command: 'dns/' . $domainID, + serverType: 'panel', + body: json_decode(json: $newDnsData, associative: true) + ); + } else { + $result = $this->apiController->sendCommand( + requestType: 'PUT', + serverName: $panel->getName(), + versionIP: 4, + apiKey: $panel->getApikey(), + command: 'dns/' . $domainID, + serverType: 'panel', + body: json_decode(json: $newDnsData, associative: true) + ); + } + if ($result['header'] == 200) { + $this->status = '200 OK'; + $this->message = 'DynDNS host successfully updated'; + } + } else { + $this->status = '404 Not Found'; + $this->message = 'Host ' . $hostName . ' not found'; + } + } else { + $this->status = '204 No content'; + $this->message = 'No content'; + } + } + } + } + } + + + /** + * @param String $host + * + * @return string + */ + private function getDomain(string $host): string + { + $host = strtolower(string: trim(string: $host)); + $count = substr_count(haystack: $host, needle: '.'); + if ($count == 2) { + if (strlen(string: explode(separator: '.', string: $host)[1]) > 3) { + $host = explode(separator: '.', string: $host, limit: 2)[1]; + } + } elseif ($count > 2) { + $host = $this->getDomain(host: explode(separator: '.', string: $host, limit: 2)[1]); + } + return $host; + } + - if (empty($apiKey)) { - $this->status = "401 Unauthorized"; - $this->message = "API key is missing."; - return false; - } else { - [$prefix,] = explode(separator: '.', string: $apiKey); - if ($apiResult = $this->apikeyRepository->findByPrefix(prefix: $prefix)) { - $storedHash = $apiResult->getApiToken(); - if (!password_verify(password: $apiKey, hash: $storedHash)) { - $this->status = "401 Unauthorized"; - $this->message = "API key mismatch."; - return false; - } - } else { - $this->status = "401 Unauthorized"; - $this->message = "Invalid API key."; - return false; - } - } - return true; - } - - - /** - * @return void - */ - private function handleDomainsGetRequest(): void - { - $name = $this->uri[3] ?? ''; - - if ($name == 'name') { - if ($result = $this->domainRepository->findByName(name: $this->uri[4])) { - $domain = [ - 'id' => $result->getId(), - 'name' => $result->getName(), - 'panel' => $result->getPanel() - ]; - $this->result = $domain; - } else { - $this->status = "404 Not Found "; - $this->message = "The specified domain was not found."; - } - } else { - if (empty($name)) { - $this->handleAllDomainsGetRequest(); - } else { - $id = intval(value: $name); - if ($id > 0) { - if ($result = $this->domainRepository->findById(id: $id)) { - $domain = [ - 'id' => $result->getId(), - 'name' => $result->getName(), - 'panel' => $result->getPanel() - ]; - $this->result = $domain; - } else { - $this->status = "404 Not Found "; - $this->message = "The specified domain was not found."; - } - } else { - $this->status = "400 Bad Request"; - $this->message = "You need to supply an ID or user the /domain/name/ path."; - - } - } - } - } - - - /** - * @return void - */ - private function handleDomainsPostRequest(): void - { - $name = $_POST['name'] ?? ''; - $panel = $_POST['panel'] ?? ''; - if (empty($name)) { - $this->status = "400 Bad Request"; - $this->message = "A name is required"; - } else { - if (empty($panel)) { - $this->status = "400 Bad Request"; - $this->message = "A panel ID is required."; - } else { - if ($this->domainRepository->findByName(name: $name)) { - $this->status = "400 Bad request"; - $this->message = "Domain: $name already exists."; - } else { - $domain = new Domain(name: $name, panel: $panel); - if ($result = $this->domainRepository->insert(domain: $domain)) { - $this->status = "201 Created"; - $this->domainController->createSlaveZoneFile(domain: $domain); - } else { - $this->status = "500 Server error"; - } - $this->message = $result; - } - } - } - } - - - /** - * @return void - */ - private function handleDomainsPutRequest(): void - { - $putData = fopen(filename: 'php://input', mode: 'r'); - $data = fread(stream: $putData, length: 8192); - $params = explode(separator: '&', string: $data); - - foreach ($params as $param) { - [$key, $value] = explode(separator: '=', string: $param); - $put[$key] = $value; - } - $id = $put['id'] ?? 0; - $name = $put['name'] ?? ''; - $panel = $put['panel'] ?? ""; - - if ($id == 0) { - $this->status = "400 Bad Request"; - $this->message = "An ID is required"; - } else { - if (!$this->domainRepository->findByID(id: $id)) { - $this->status = "404 Not Found"; - $this->message = "Domain with ID : $id doesn't exist."; - } else { - $domain = new Domain(name: $name, panel: $panel, id: $id); - $this->domainRepository->update(domain: $domain); - $this->status = "201 Updated"; - $this->message = "201 Updated"; - $this->domainController->createSlaveZoneFile(domain: $domain); - } - } - } - - - /** - * @return void - */ - private function handleDomainsDeleteRequest(): void - { - $deleteData = fopen(filename: 'php://input', mode: 'r'); - $data = fread(stream: $deleteData, length: 512); - $params = explode(separator: '&', string: $data); - - foreach ($params as $param) { - [$key, $value] = explode(separator: '=', string: $param); - $delete[$key] = $value; - } - - $id = $delete['id'] ?? 0; - - if ($id == 0) { - $this->status = "400 Bad Request"; - $this->message = "You need to supply an ID."; - } else { - - if (!$domain = $this->domainRepository->findByID(id: $id)) { - $this->status = "400 Bad Request"; - $this->message = "There is no domain with ID $id."; - } else { - $this->domainRepository->delete(domain: $domain); - $this->status = "204 No content."; - $this->message = "The domain $id has been deleted."; - } - } - } - - - private function handleDynDNS(): void - { - $this->logger->debug(message: 'handleDynDNS()'); - - if ($this->checkPassword()) { - $host = $this->uri[3] ?? ''; - - if (empty($host)) { - $this->status = '400 Bad Request'; - } else { - $a = $_POST['a'] ?? ''; - $aaaa = $_POST['aaaa'] ?? ''; - - if (empty($a) && empty($aaaa)) { - $address = $_SERVER['REMOTE_ADDR']; - - if (filter_var(value: $address, filter: FILTER_VALIDATE_IP, options: FILTER_FLAG_IPV6)) { - $aaaa = $address; - } else { - $a = $address; - } - } - - $this->logger->debug(message: 'a: ' . $a); - $this->logger->debug(message: 'aaaa: ' . $aaaa); - - - $domainName = $this->getDomain(host: $host); - $hostName = str_replace(search: '.' . $domainName, replace: '', subject: $host); - if (!$domain = $this->domainRepository->findByName(name: $domainName)) { - $this->status = '404 Not Found'; - $this->message = 'Domain ' . $domainName . ' not found'; - } else { - // check if address has changed - if ($dynDNS = $this->dynDNSRepository->findByName(name: $host)) { - $this->logger->debug(message: 'found host: ' . $host); - $this->logger->debug(message: "a: $a"); - $this->logger->debug(message: "aaaa: $aaaa"); - - $ipChanged = false; - - if (!empty($a)) { - if ($a != $dynDNS->getA()) { - $this->logger->debug(message: $a . ' != ' . $dynDNS->getA()); - $dynDNS->setA(a: $a); - $ipChanged = true; - } - } - - if (!empty($aaaa)) { - if ($aaaa != $dynDNS->getAaaa()) { - $this->logger->debug(message: $aaaa . ' != ' . $dynDNS->getAaaa()); - $dynDNS->setAaaa(aaaa: $aaaa); - $ipChanged = true; - } - } - - if ($ipChanged) { - $this->dynDNSRepository->update(dynDNS: $dynDNS); - } - } else { - $dynDNS = new DynDNS(name: $host, a: $a, aaaa: $aaaa); - $this->dynDNSRepository->insert(dynDNS: $dynDNS); - $ipChanged = true; - } - - - if ($ipChanged) { - $panel = $this->panelRepository->findByName(name: $domain->getPanel()); - - if (!empty($panel->getAaaa())) { - $domainData = $this->apiController->sendCommand( - requestType: 'GET', - serverName : $panel->getName(), - versionIP : 6, - apiKey : $panel->getApikey(), - command : 'domains/name/' . $domainName, - serverType : 'panel'); - } else { - $domainData = $this->apiController->sendCommand( - requestType: 'GET', - serverName : $panel->getName(), - versionIP : 4, - apiKey : $panel->getApikey(), - command : 'domains/name/' . $domainName, - serverType : 'panel'); - } - - $domainDecodedData = json_decode(json: $domainData['data']); - $domainID = $domainDecodedData->id; - - if (!empty($panel->getAaaa())) { - $dnsData = $this->apiController->sendCommand( - requestType: 'GET', - serverName : $panel->getName(), - versionIP : 6, - apiKey : $panel->getApikey(), - command : 'dns/' . $domainID, - serverType : 'panel'); - } else { - $dnsData = $this->apiController->sendCommand( - requestType: 'GET', - serverName : $panel->getName(), - versionIP : 4, - apiKey : $panel->getApikey(), - command : 'dns/' . $domainID, - serverType : 'panel'); - } - - $dnsDataDecoded = json_decode(json: $dnsData['data']); - $soa = $dnsDataDecoded->records->soa; - $others = $dnsDataDecoded->records->other; - - $hostFound = false; - - $updateHost = function (object $host) use ($hostName, $a, $aaaa, &$hostFound) { - if ($host->host == $hostName) { - $hostFound = true; - if ($host->type == 'A') { - if (!empty($a)) { - $host->value = $a; - } - } else { - if (!empty($aaaa)) { - $host->value = $aaaa; - } - } - } - }; - - array_map(callback: $updateHost, array: $others); - - if ($hostFound) { - $newDnsData = json_encode(value: [ - 'records' => [ - 'soa' => $soa, - 'other' => $others - ] - ]); - - if (!empty($panel->getAaaa())) { - $result = $this->apiController->sendCommand( - requestType: 'PUT', - serverName : $panel->getName(), - versionIP : 6, - apiKey : $panel->getApikey(), - command : 'dns/' . $domainID, - serverType : 'panel', - body : json_decode(json: $newDnsData, associative: true) - ); - } else { - $result = $this->apiController->sendCommand( - requestType: 'PUT', - serverName : $panel->getName(), - versionIP : 4, - apiKey : $panel->getApikey(), - command : 'dns/' . $domainID, - serverType : 'panel', - body : json_decode(json: $newDnsData, associative: true) - ); - } - if ($result['header'] == 200) { - $this->status = '200 OK'; - $this->message = 'DynDNS host successfully updated'; - } - } else { - $this->status = '404 Not Found'; - $this->message = 'Host ' . $hostName . ' not found'; - } - } else { - $this->status = '204 No content'; - $this->message = 'No content'; - } - } - } - } - } - - - /** - * @param String $host - * - * @return string - */ - private function getDomain(string $host): string - { - $host = strtolower(string: trim(string: $host)); - $count = substr_count(haystack: $host, needle: '.'); - if ($count == 2) { - if (strlen(string: explode(separator: '.', string: $host)[1]) > 3) { - $host = explode(separator: '.', string: $host, limit: 2)[1]; - } - } elseif ($count > 2) { - $host = $this->getDomain(host: explode(separator: '.', string: $host, limit: 2)[1]); - } - return $host; - } - - }