📁
SKYSHELL MANAGER
PHP v8.2.31
Create
Create
Path:
root
/
home
/
thevaxnx
/
nativize.com
/
staging
/
wp-includes
/
js
/
tinymce
/
themes
/
Name
Size
Perm
Actions
📁
inlite
-
0755
🗑️
🏷️
🔒
📁
modern
-
0755
🗑️
🏷️
🔒
📄
wp-links-opml.php
6.83 KB
0444
🗑️
🏷️
⬇️
✏️
🔒
Edit: Certificate.php
<?php namespace App\Service\Certificate; use App\Exception\CertificateException; use App\Exception\CertificateNotFoundException; 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; use App\Model\CertificateView; class Certificate { const CODE_CANT_GET_NC_USER_ERROR = 2200; const SENSYTIVE_DATA_KEYS = ['privatekeyId']; const STATUS_FAIL = 'fail'; const STATUS_SUCCESS = 'success'; public const CODE_CERTIFICATE_ALREADY_EXISTS = 20; public const CODE_CERTIFICATE_LIMIT_REACHED = 30; 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']); $this->handleCertificateTypeReplacement($certData); } 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; } /** * If Core replaced the requested product (e.g. Positive SSL -> Standard SSL), update the * transfer's certType/vendor to the real issued type. No-op unless the assumed product is a * Comodo CA (the only replaceable case). Never throws — failure keeps the assumed type. * * @param CertificateTransfer $certData * * @return void */ public function handleCertificateTypeReplacement(CertificateTransfer $certData): void { $certificateId = $certData->getCertificateId(); $isCertificateNotCreated = in_array($certData->getCurrentCode(), [ self::CODE_CERTIFICATE_ALREADY_EXISTS, self::CODE_CERTIFICATE_LIMIT_REACHED, ], true); if (!$certificateId || $isCertificateNotCreated) { return; } try { $isComodoCa = $this->productManager->isComodoCa($certData->getCertType()); } catch (\Throwable) { return; // unknown type → keep the assumed type, never throw to the caller } if (!$isComodoCa) { return; } $logPayload = [ 'certificateId' => $certData->getCertificateId(), 'certificateType' => $certData->getCertType(), 'domainName' => $certData->getDomainName(), 'userName' => $certData->getCPanelUser(), ]; try { $certificate = $this->ncGatewayApi->getInfo( $certData->getCertificateId(), true, $certData->getNCUser() ); $certificateType = $certificate['type'] ?? ''; if ($certificateType !== '' && strtolower($certificateType) !== strtolower($certData->getCertType())) { $vendor = strtolower($this->productManager->getCaName($certificateType)); $certData ->setCertType($certificateType) ->setVendor($vendor); $this->logger->notice('Certificate type replacement applied', array_merge( $logPayload, ['certificateNewType' => $certificateType] )); } } catch (\Throwable $e) { $this->logger->warning('Failed to apply certificate type replacement; keeping assumed type', array_merge( $logPayload, ['errorMessage' => $e->getMessage()] )); } } public function getExpiringCertificates(): array { return $this->certificateRepository->getExpiringCertificates(); } public function getCertificatesReadyForReissue(): array { $certificatesReadyForReissue = []; $expiringCertificates = $this->certificateRepository->getExpiringCertificates(); /** @var CertificateEntity[] $expiringCertificates */ foreach ($expiringCertificates as $certificate) { if($certificate->isReissueRequired()) { $certificatesReadyForReissue[] = $certificate; } } return $certificatesReadyForReissue; } public function updateSubscriptionExpires(CertificateEntity $certificate): void { try { $certificateInfo = $this->ncGatewayApi->getInfo($certificate->getNcId(), true, $certificate->getUser()->getNcLogin()); $certificate->setSubscriptionExpires($certificateInfo['subscription_expires']); } catch (CertificateNotFoundException $e) { $this->markIneligible($certificate); $this->logger->info('Failed to update subscription_expires. Certificate is not found for the user account, marked as INELIGIBLE', [ 'ncId' => $certificate->getNcId(), 'ncUser' => $certificate->getUser()->getNcLogin(), ]); } catch (\Exception $e) { $message = sprintf('Failed to update subscription expires for certificate ID %d: %s', $certificate->getNcId(), $e->getMessage()); $this->logger->error($message); } } /** * Mark a certificate as ineligible: Namecheap no longer recognises the certificate id as * belonging to the user's account. Terminal — the physical cPanel certificate is left in place. */ public function markIneligible(CertificateEntity $certificate): void { $certificate->setStatus(CertificateEntity::STATUS_INELIGIBLE); $this->entityManager->flush(); $this->logger->info('Mark certificate ineligible', [ 'ncId' => $certificate->getNcId(), 'ncUser' => $certificate->getNcUser(), ]); } public function markAutoReissueAsStarted(CertificateEntity $certificate): void { $certificate->setAutoReissueStarted(true); $this->entityManager->flush(); } /** * @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); try { $userCertificatesFromCpanelDb = $this->syncMissingSubscriptionExpires($userCertificatesFromCpanelDb); } catch (\Throwable $e) { $this->logger->error('Failed to sync missing subscription_expires on installed page', [ 'errorMessage' => $e->getMessage(), ]); } $userCertificatesFromCpanelDb = $this->clearSensitiveData($userCertificatesFromCpanelDb); $userCertificatesFromCpanelDb = $this->addLinkToCertificate($userCertificatesFromCpanelDb); $cleanDomains = $this->getCertificateDomains($userCertificatesFromCpanelDb); $userCertificatesFromCpanelDb = $this->addCertificateHttpStatus($userCertificatesFromCpanelDb, $cleanDomains); $userCertificatesFromCpanelDb = $this->addRemainingDays($userCertificatesFromCpanelDb); 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 { $certificate = $this->certificateRepository->findOneBy(['ncId' => $ncId]); if ($certificate !== null && $certificate->isIneligible()) { return [ 'status' => self::STATUS_SUCCESS, 'message' => '', ]; } try { $this->certificateRepository->updateToggle($ncId, $statusRedirect); } catch (\Exception $e) { $this->logger->error($e->getMessage(), [$domain]); return [ 'status' => self::STATUS_FAIL, 'message' => $e->getMessage(), ]; } 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 array */ private function addRemainingDays(array $certificates): array { foreach ($certificates as $key => $certificate) { $view = new CertificateView($certificate); $certificates[$key]['certificateRemainingDays'] = $view->calculateCertificateRemainingDays(); $certificates[$key]['subscriptionRemainingDays'] = $view->calculateSubscriptionRemainingDays(); } return $certificates; } /** * @param array $certificates * * @return bool */ private function hasInProgressCertificate(array $certificates): bool { return false !== array_search( CertificateEntity::STATUS_INPROGRESS, array_column($certificates, 'status') ); } /** * Filter the in-memory list returned by getCertificatesByUserName() for certificates that need * subscription_expires populated, fetch the missing values from the Namecheap Gateway one at a * time, and persist them. * * @param array $certificates Array shape from CertificateRepository::getCertificatesByUserName() * @return array Same shape; subscription_expires populated where the NC call succeeded */ private function syncMissingSubscriptionExpires(array $certificates): array { $items = $this->filterCertificatesToSyncSubscriptionExpires($certificates); if (!$items) { return $certificates; } $this->logger->info('Found certificates to sync missing subscription_expires', [ 'certificateNcIDs' => array_column($items, 'ncId'), ]); $updated = 0; foreach ($items as $key => $item) { try { $info = $this->ncGatewayApi->getInfo( (string) $item['ncId'], true, $item['ncUserName'] ); } catch (\Throwable $e) { $this->logger->error('Failed to fetch cert info to sync subscription_expires', [ 'ncId' => $item['ncId'], 'errorMessage' => $e->getMessage(), ]); continue; } if (empty($info['subscription_expires'])) { $this->logger->warning('Certificate subscription_expires is missing', [ 'ncId' => $item['ncId'], ]); continue; } $subscriptionExpires = (int) $info['subscription_expires']; $certificates[$key]['subscription_expires'] = $subscriptionExpires; $this->certificateRepository->updateSubscriptionExpiresById( (int) $certificates[$key]['id'], $subscriptionExpires ); $updated++; } if ($updated > 0) { $this->logger->info('Synced missing subscription_expires on installed page', [ 'updatedCertificates' => $updated, ]); } return $certificates; } /** * Filter Active/Expired certificates with missing `subscription_expires` * and which were not updated by sync cron or auto-reissue cron by some reason. * So, certificates will have `subscription_expires` in the response where it's necessary * @param array $certificates * @return array */ private function filterCertificatesToSyncSubscriptionExpires(array $certificates): array { $excludedNcStatuses = [ CertificateEntity::NCSTATUS_ACTIVE, CertificateEntity::NCSTATUS_EXPIRED, ]; $items = []; foreach ($certificates as $key => $certificate) { if (($certificate['status'] ?? null) === CertificateEntity::STATUS_INELIGIBLE) { continue; } if (empty($certificate['ncUser'])) { continue; } if (!empty($certificate['subscription_expires'])) { continue; } if (!in_array($certificate['ncStatus'] ?? null, $excludedNcStatuses, true)) { continue; } if (empty($certificate['expires'])) { continue; } $daysRemaining = ceil(($certificate['expires'] - time()) / (24 * 60 * 60)); if ($daysRemaining > 30) { continue; } $items[$key] = [ 'ncId' => $certificate['ncId'], 'ncUserName' => $certificate['ncUser'], ]; } return $items; } /** * @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; } }
Save