Viewing File: /usr/local/cpanel/whostmgr/docroot/cgi/ncssl/source/src/Service/NcGatewayApi/NcGatewayApi.php
<?php
namespace App\Service\NcGatewayApi;
use App\Entity\Certificate;
use App\Service\Certificate\CertificateTransfer;
use App\Service\NcGatewayApi\Exceptions\NcGatewayApiException;
use App\Service\State\StateUser;
use Exception;
use \ArrayObject;
use GuzzleHttp\Client;
use Psr\Log\LoggerInterface;
use Symfony\Component\Validator\Validation;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
class NcGatewayApi extends Caller
{
public const METHOD_HANDLE_GET_INFO = 'handleGetInfo';
public const METHOD_HANDLE_GET_LIST = 'handleGetList';
public const METHOD_GET_FREE_CERTIFICATES_INFO = 'getFreeCertificatesInfo';
public const METHOD_GET_CERTIFICATE = 'getCertificate';
public const METHOD_ACTIVATE_CERTIFICATE = 'activateCertificate';
public const METHOD_REISSUE_CERTIFICATE = 'reissueCertificate';
public const ERR_CODE_WRONG_USERNAME = 4010;
public const ERR_CANT_GET_NC_USER_ERROR = 2200;
public const CONST_GET_LIST_PAGE = 1;
public const CONST_GET_LIST_MAX_PAGE_SIZE = 99;
public const CONST_GET_LIST_MAX_ITERATIONS = 100;
public const GATEWAY_DELAY = 10;
public const GATEWAY_RETRY_LIMIT = 3;
public function __construct(
#[Autowire(env: 'NC_GATEWAY_API_URL')]
private readonly string $apiUrl,
#[Autowire(env: 'NC_GATEWAY_API_ACCESS_TOKEN')]
private readonly string $gatewayAccessToken,
#[Autowire(service: 'guzzle_client')]
private readonly Client $client,
private readonly StateUser $stateUser,
private readonly LoggerInterface $gatewayApiLogger,
) {
parent::__construct($this->apiUrl, $this->gatewayAccessToken, $this->client);
}
/**
* @param array $parameters
*
* @return array
* @throws NcGatewayApiException
* @throws Exception
*/
public function getCertificate(array $parameters): array
{
$scheme = $this->createSchemeGetCertificate();
$this->checkValidation($parameters, $scheme);
return $this->makeCall(self::METHOD_GET_CERTIFICATE, $parameters);
}
/**
* @param CertificateTransfer $certificateTransfer
* @param string $csr
* @param bool $isAsyncExternalCall
*
* @return array
* @throws NcGatewayApiException
* @throws Exception
*/
public function activate(CertificateTransfer $certificateTransfer, string $csr, bool $isAsyncExternalCall): array
{
$parameters = [
'certificateId' => (string) $certificateTransfer->getCertificateId(),
'csr' => $csr,
'username' => $certificateTransfer->getNCUser(),
];
if ($isAsyncExternalCall) {
$parameters['async'] = true;
}
$adminEmailAddress = $certificateTransfer->getAdminEmail();
if ($adminEmailAddress) {
$parameters['adminEmailAddress'] = $adminEmailAddress;
}
$scheme = $this->createSchemeForActivate();
$this->checkValidation($parameters, $scheme);
return $this->makeCall(self::METHOD_ACTIVATE_CERTIFICATE, $parameters);
}
/**
* @param string $certificateId
* @param string $csr
* @param string $userName
* @param string $adminEmailAddress
*
* @return array
* @throws NcGatewayApiException
* @throws Exception
*/
public function reissue(string $certificateId, string $csr, string $userName, string $adminEmailAddress): array
{
$parameters = [
'certificateId' => $certificateId,
'csr' => $csr,
'username' => $userName
];
if ($adminEmailAddress) {
$parameters['adminEmailAddress'] = $adminEmailAddress;
}
$scheme = $this->createSchemeForReissue();
$this->checkValidation($parameters, $scheme);
return $this->makeCall(self::METHOD_REISSUE_CERTIFICATE, $parameters);
}
/**
* @param $id
* @param $returnCert
* @param $userName
*
* @return array
* @throws NcGatewayApiException
*/
public function getInfo($id, $returnCert, $userName): array
{
$parameters = [
'CertificateID' => $id,
'ncUserName' => $userName
];
if ($returnCert) {
$parameters['returncertificate'] = 'true';
$parameters['returntype'] = 'individual';
}
$scheme = $this->createSchemeForGetInfo();
$this->checkValidation($parameters, $scheme);
$certificate = $this->makeCall(self::METHOD_HANDLE_GET_INFO, $parameters);
if ($certificate['status'] === Certificate::NCSTATUS_NEWPURCHASE) {
$certificate['common_name'] = '';
}
$certificate['expires'] = $certificate['expires'] != '' ? strtotime($certificate['expires']) : 0;
$certificate['activation_expire_date'] = $certificate['activation_expire_date'] != '' ? strtotime($certificate['activation_expire_date']) : 0;
$certificate['issued_on'] = $certificate['issued_on'] != '' ? strtotime($certificate['issued_on']) : 0;
return $certificate;
}
/**
* @return array
* @throws Exception
*/
public function getFreeCertificatesInfo(): array
{
return $this->makeCall(self::METHOD_GET_FREE_CERTIFICATES_INFO, [
'userName' => $this->stateUser->getUser()->getName(),
'cPanelServer' => gethostname()
]);
}
/**
* @param string $list_type
* @param string $search_query
* @param string $sort_by
*
* @return array
* @throws Exception
*/
public function getSslList(string $list_type = 'ALL', string $search_query = '', string $sort_by = 'PURCHASEDATE_DESC'): array
{
$certs = [];
$parameters = [
'ncUserName' => $this->stateUser->getUser()->getNcLogin(),
'PageSize' => self::CONST_GET_LIST_MAX_PAGE_SIZE,
'Page' => self::CONST_GET_LIST_PAGE,
'ListType' => $list_type,
'SortBy' => $sort_by,
];
if ($search_query !== '') {
$parameters['SearchTerm'] = $search_query;
}
for ($i = 0; $i < self::CONST_GET_LIST_MAX_ITERATIONS; $i++) {
$response = $this->makeCall(self::METHOD_HANDLE_GET_LIST, $parameters);
foreach ($response['certificatesList'] as $certInfo) {
$certInfo['status'] = strtoupper($certInfo['status']);
if ($certInfo['status'] === Certificate::NCSTATUS_NEWPURCHASE) {
$certInfo['common_name'] = '';
}
$certs[] = $certInfo;
}
$total_items = (int)$response['meta']['totalItems'];
if (($parameters['Page'] * $parameters['PageSize']) >= $total_items || $total_items == 0) {
break;
}
++$parameters['Page'];
}
return $certs;
}
/**
* @return Assert\Collection
*/
protected function createSchemeForReissue(): Assert\Collection
{
return new Assert\Collection([
'certificateId' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
'csr' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
'username' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
], allowExtraFields: true);
}
/**
* @return Assert\Collection
*/
protected function createSchemeForActivate(): Assert\Collection
{
return new Assert\Collection([
'certificateId' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
'username' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
'csr' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
], allowExtraFields: true);
}
/**
* @return Assert\Collection
*/
protected function createSchemeGetCertificate(): Assert\Collection
{
return new Assert\Collection([
'cPanelServer' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
'userName' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
'domainName' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
], allowExtraFields: true);
}
/**
* @return Assert\Collection
*/
protected function createSchemeForGetInfo(): Assert\Collection
{
return new Assert\Collection([
'CertificateID' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
'ncUserName' => new Assert\Required([
new Assert\NotBlank(),
new Assert\Type('string'),
]),
'returncertificate' => new Assert\Optional([
new Assert\Type('string'),
]),
'returntype' => new Assert\Optional([
new Assert\Type('string'),
]),
], allowExtraFields: true);
}
/**
* @param array $parameters
* @param mixed $scheme
*
* @return void
* @throws NcGatewayApiException
*/
protected function checkValidation(array $parameters, mixed $scheme): void
{
$validator = Validation::createValidator();
$errors = $validator->validate($parameters, $scheme);
if (count($errors) > 0) {
throw new NcGatewayApiException('Invalid parameters');
}
}
/**
* @param string $method
* @param array $parameters
* @param bool $loggerEnabled
*
* @return array
* @throws Exception
*/
public function makeCall(string $method = '', array $parameters = [], bool $loggerEnabled = true): array
{
$retryCounter = 0;
do {
try {
$response = $this->call($method, $parameters);
if ($loggerEnabled) {
$this->gatewayApiLogger->info('Nc Gateway request & response', [
'method' => $method,
'url' => $this->apiUrl,
'request' => json_encode($parameters, JSON_THROW_ON_ERROR),
'response' => $response ? json_encode($this->removeSensitiveInfo($response), JSON_THROW_ON_ERROR) : '[empty response]'
]);
}
return $response;
} catch (Exception $e) {
$this->handleError($e, $retryCounter++);
}
} while (true);
}
/**
* @param Exception $e
* @param int $attempt
*
* @return void
* @throws Exception
*/
private function handleError(Exception $e, int $attempt): void
{
$message = $e->getMessage();
if ($e->getCode() === self::ERR_CODE_WRONG_USERNAME) {
$message = 'Invalid parameters: "userName"';
}
if ($e->getCode() === self::ERR_CANT_GET_NC_USER_ERROR) {
if ($attempt !== self::GATEWAY_RETRY_LIMIT) {
$logContext['error'] = sprintf('Error. Code (%s), Message: (%s), Attempt: (%s)', $e->getCode(), $message, $attempt);
$this->gatewayApiLogger->error($message, $logContext);
sleep(self::GATEWAY_DELAY);
return;
}
$message = 'Can\'t get NC user for: "userName"';
}
$logContext['error'] = sprintf('Error. Code (%s), Message: (%s)', $e->getCode(), $message);
$this->gatewayApiLogger->error($message, $logContext);
throw $e;
}
/**
* @param array $content
* @return array
*/
protected function removeSensitiveInfo(array $content = []): array
{
$contentObject = new ArrayObject($content);
$result = $contentObject->getArrayCopy();
if (isset($result['ca_certs'])) {
$result['ca_certs'] = '';
}
if (isset($result['cert_body'])) {
$result['cert_body'] = '';
}
if (isset($result['csr'])) {
$result['csr'] = '';
}
return $result;
}
}
Back to Directory
File Manager