Viewing File: /usr/local/cpanel/whostmgr/docroot/cgi/ncssl/source/src/Service/Certificate/Certificate.php

<?php

namespace App\Service\Certificate;

use App\Exception\CertificateException;
use App\Repository\CertificateRepository;
use App\Service\NcGatewayApi\Exceptions\NcGatewayApiException;
use App\Service\NcGatewayApi\NcGatewayApi;
use App\Service\NcPlugin\PluginException;
use App\Service\PluginGateway\NcCoreApi;
use App\Service\State\StateUser;
use App\Service\Manager\HttpsRedirectManager;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use App\Entity\Certificate as CertificateEntity;

class Certificate
{
    const CODE_CANT_GET_NC_USER_ERROR = 2200;
    const SENSYTIVE_DATA_KEYS = ['privatekeyId'];
    const STATUS_FAIL = 'fail';
    const STATUS_SUCCESS = 'success';

    public function __construct(
        private readonly NcGatewayApi $ncGatewayApi,
        private readonly NcCoreApi $ncApi,
        private readonly StateUser $stateUser,
        private readonly CertificateRepository $certificateRepository,
        private readonly EntityManagerInterface $entityManager,
        private readonly ProductManager $productManager,
        private readonly HttpsRedirectManager $httpsRedirectManager,
        private readonly LoggerInterface $logger,
    ) { }

    /**
     * @param CertificateTransfer $certData
     * @return CertificateTransfer
     * @throws CertificateException
     */
    public function getCertificate(CertificateTransfer $certData): CertificateTransfer
    {
        try {
            $result = $this->ncGatewayApi->getCertificate([
                'cPanelServer' => $certData->getCPanelServer(),
                'userName' => $certData->getCPanelUser(),
                'domainName' => $certData->getDomainName(),
                'certificateType' => $certData->getCertType(),
            ]);

            $certData->setCurrentCode($result['code']);

            if ($result['ncUser']) {
                $certData->setNCUser($result['ncUser']);
            }
            if ($result['certificateId']) {
                $certData->setCertificateId($result['certificateId']);
            }

            $certData->setFreeTotal($result['freeTotal']);
        } catch (NcGatewayApiException $e) {
            $message = sprintf('NcGatewayApi error: %s', $e->getMessage());
            $this->logger->error($message, $e->getData());

            throw new CertificateException($message, $e->getCode(), $e, $e->getData());
        } catch (PluginException $e) {
            $message = sprintf('Plugin Exception error: %s', $e->getMessage());
            $this->logger->error($message, [$certData->getDomainName()]);

            throw new CertificateException($message, $e->getCode(), $e, $e->getMessage());
        } catch (\Exception $e) {
            throw new CertificateException($e->getMessage(), $e->getCode(), $e, $e->getMessage());
        }

        return $certData;
    }

    /**
     * @return array
     * @throws PluginException
     * @throws \App\Service\NcPlugin\InvalidAccessTokenNcApiException
     * @throws \App\Service\NcPlugin\NcApiException
     */
    public function getCertificatesThatCanBeInstalled(): array
    {
        $ssls = [];
        $sslsInstalledIds = [];
        $userId = $this->stateUser->getUser()->getId();

        $userCertificatesFromCpanelDb = $this->certificateRepository->getCertificatesByUserId($userId);

        foreach ($userCertificatesFromCpanelDb as $row) {
            $sslsInstalledIds[] = $row->getNcId();
        }
        $allowedStatuses = [
            CertificateEntity::NCSTATUS_ACTIVE,
            CertificateEntity::NCSTATUS_NEWPURCHASE,
            CertificateEntity::NCSTATUS_NEWRENEWAL,
            CertificateEntity::NCSTATUS_EXPIRED,
        ];
        $sslsWithAllowedStatuses = $this->ncApi->getSslListWithStatuses($allowedStatuses);
        foreach ($sslsWithAllowedStatuses as $ssl) {
            $ssl['discontinued'] = !$this->productManager->isAvailable($ssl['type']);
            $isSingleDv = $this->isSingleType($ssl['type']);

            if ($isSingleDv && !in_array($ssl['id'], $sslsInstalledIds)) {
                $ssl['host'] = $this->prepareHost($ssl['common_name']);
                $ssls[] = $ssl;
            }
        }

        // sort id desc
        uasort($ssls, function ($a, $b) {
            return ($a['id'] < $b['id']) ? 1 : -1;
        });

        return [
            'certificates' => $ssls,
            'freeCertificatesInfo' => $this->getFreeCertificatesInfo(),
        ];
    }

    /**
     * @return array
     * @throws \Exception
     */
    public function getInstalledCertificates(): array
    {
        $userName = $this->stateUser->getUser()->getName();

        $userCertificatesFromCpanelDb = $this->certificateRepository->getCertificatesByUserName($userName);
        $userCertificatesFromCpanelDb = $this->clearSensitiveData($userCertificatesFromCpanelDb);
        $userCertificatesFromCpanelDb = $this->addLinkToCertificate($userCertificatesFromCpanelDb);
        $cleanDomains = $this->getCertificateDomains($userCertificatesFromCpanelDb);
        $userCertificatesFromCpanelDb = $this->addCertificateHttpStatus($userCertificatesFromCpanelDb, $cleanDomains);

        return [
            'certificates'=> $userCertificatesFromCpanelDb,
            'certsGrouped'=> $this->getCertificatesGroupedByDomain($userCertificatesFromCpanelDb),
            'freeCertificatesInfo'=> $this->getFreeCertificatesInfo(),
        ];
    }

    /**
     * @return array
     */
    public function getCertificatesForLocalDbUpdate(): array
    {
        $userId = $this->stateUser->getUser()->getId();
        $userNcLogin = $this->stateUser->getUser()->getNcLogin();

        if(!$userId || !$userNcLogin) {
            return [];
        }

        return $this->certificateRepository->getCertificatesForLocalDbUpdate($userId, $userNcLogin);
    }

    /**
     * @param int $id
     *
     * @return void
     */
    public function deleteById(int $id): void
    {
        $userId = $this->stateUser->getUser()->getId();
        $this->certificateRepository->deleteById($id, $userId);
    }

    /**
     * @param int $certificateId
     * @param bool $statusRedirect
     * @param string $domain
     *
     * @return false|array
     */
    public function updateToggle(int $ncId, bool $statusRedirect, string $domain): false|array
    {
        try {
            $this->certificateRepository->updateToggle($ncId, $statusRedirect);
        } catch (\Exception $e) {
            $this->logger->error($e->getMessage(), [$domain]);
             return [
                'status' => self::STATUS_FAIL,
                'message' => $e->getMessage(),
             ];
        }

        $certificate = $this->certificateRepository->findOneBy(['ncId' => $ncId]);

        if ($certificate->getStatus() != CertificateEntity::STATUS_ACTIVE) {
            return [
                'status' => self::STATUS_SUCCESS,
                'message' => '',
            ];
        }

        try {
            $result = $this->httpsRedirectManager->toggleHttpRedirect($domain, $statusRedirect);
        } catch (\JsonException $e) {
            return [
                'status' => self::STATUS_FAIL,
                'message' => $e->getMessage(),
            ];
        }

        return $result;
    }

    /**
     * @param int $certificateId
     * @param string $ncStatus
     *
     * @return void
     */
    public function updateNcStatus(int $certificateId, string $ncStatus): void
    {
        $certificate = $this->certificateRepository->findOneBy(['id' => $certificateId]);
        $certificate->setNcStatus($ncStatus);

        $this->entityManager->flush();
    }

    /**
     * @return array
     */
    public function getFreeCertificatesInfo(): array
    {
        try {
            $freeCertificatesInfo = $this->ncGatewayApi->getFreeCertificatesInfo();
        } catch (\Exception $e) {
            $this->logger->error($e->getMessage(), $e->getData());
            $freeCertificatesInfo = [];
        }

        return $freeCertificatesInfo;
    }

    /**
     * @param string $sslType
     *
     * @return bool
     * @throws PluginException
     */
    private function isSingleType(string $sslType): bool
    {
        return $sslType == 'quickssl premium'
            || !(
                $this->productManager->isWildcard($sslType)
                || $this->productManager->isMdc($sslType)
                || !$this->productManager->isDV($sslType)
            );
    }

    /**
     * @param string $commonName
     *
     * @return string
     */
    private function prepareHost(?string $commonName): ?string
    {
        if (!$commonName) {
            return $commonName;
        }

        if (str_starts_with($commonName, 'www.')) {
            $commonName = substr($commonName, 4);
        }
        if (str_starts_with($commonName, '*.')) {
            $commonName = substr($commonName, 2);
        }

        return $commonName;
    }

    /**
     * @param array $certificates
     *
     * @return array
     * @throws PluginException
     */
    private function addLinkToCertificate(array $certificates): array
    {
        foreach ($certificates as $key => $certificate) {
            if ($this->productManager->isWildcard($certificate['type'])) {
                $certificates[$key]['link'] = $certificate['host'];
            } else {
                $certificates[$key]['link'] = $certificate['commonName'];
            }
        }

        return $certificates;
    }

    /**
     * @param array $certificates
     *
     * @return array
     */
    private function getCertificatesGroupedByDomain(array $certificates = []): array
    {
        $certGrouped = [];
        foreach ($certificates as $certificate) {
            $certGrouped[$certificate['commonName']][] = $certificate;
        }

        return $certGrouped;
    }

    /**
     * @param array $certificates
     *
     * @return array
     */
    private function getCertificateDomains(array $certificates = []): array
    {
        $domains = [];
        foreach ($certificates as $key => $certificate) {
            $domains[$key] = HttpsRedirectManager::getDomainWithoutWww($certificates[$key]['link']);
        }

        return $domains;
    }

    /**
     * @param array $certificates
     * @param array $domains
     *
     * @return array
     */
    private function addCertificateHttpStatus(array $certificates = [], array $domains = []): array
    {
        $httpsStatuses = $this->httpsRedirectManager->getHttpsStatuses(array_values($domains));

        if (count($httpsStatuses)) {
            foreach ($certificates as $key => &$certificate) {
                if (array_key_exists($domains[$key], $httpsStatuses)) {
                    $certificate['isHttpsStatusOn'] = (bool)$httpsStatuses[$domains[$key]];
                } else {
                    $certificate['isHttpsStatusOn']  = null;
                }

            }
        }

        return $certificates;
    }

    /**
     * @param array $certificates
     *
     * @return bool
     */
    private function hasInProgressCertificate(array $certificates): bool
    {
        return false !== array_search(
                CertificateEntity::STATUS_INPROGRESS, array_column($certificates, 'status')
            );
    }

    /**
     * @param array $certificates
     *
     * @return array
     */
    private function clearSensitiveData(array $certificates): array
    {
        foreach ($certificates as &$certificate) {
            foreach (self::SENSYTIVE_DATA_KEYS as $key) {
                if (array_key_exists($key, $certificate)) {
                    unset($certificate[$key]);
                }
            }
        }

        return $certificates;
    }
}
Back to Directory File Manager