HEX
Server: Apache
System: Linux hz.vslconceptsdomains.com 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
User: dkfounda (3233)
PHP: 8.1.34
Disabled: exec,passthru,shell_exec,system
Upload Files
File: //usr/local/mailchannels/clients/InboundApi/InboundApiImpl.php
<?php
namespace MailChannels;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;
use Psr\Http\Message\ResponseInterface;

class InboundApiImpl implements InboundApi {
    const MAXIMUM_DOWNSTREAM_ADDRESSES = 10;
    const MAXIMUM_TARGET_LENGTH = 255;

    private $client;
    private $logger;

    public function __construct($baseUri, $apiKey, Client $client=null) {
        if(!$client) {
            $client = new Client([
                'base_uri'=>$baseUri,
                'headers'=>[
                    'X-Api-Key'=>$apiKey,
                    'Accept'=>'application/json'
                ],
                'verify' => APP::verifySSL()
            ]);
        }
        $this->client = $client;

        $this->logger = \MailChannels\App::getLogger();
    }

    /**
     * @param $domain
     * @param $subscriptionHandle
     * @return Domain|WHM\Domain
     * @throws InboundApiConflictException
     * @throws InboundApiException
     * @throws InboundApiForbiddenException
     * @throws InboundApiInternalServerErrorException
     * @throws InboundApiUnauthorizedException
     */
    public function provisionDomain($domain, $subscriptionHandle) {
        if(!is_string($domain) || !is_string($subscriptionHandle)) {
            throw new InboundApiException("arguments are not of string");
        }

        $uri = "domains";

        $requestBody = [
            'domain' => $domain,
            'subscriptionHandle' => $subscriptionHandle
        ];

        try {
            $response = $this->call('POST', $uri, [
                'headers' => [
                    'Content-Type' => 'application/json'
                ],
                'body' => json_encode($requestBody)
            ]);

            $jsonResponse = json_decode($response->getBody()->getContents());
            if(!in_array((int) $response->getStatusCode(), [200, 201])) {
                throw new InboundApiInternalServerErrorException("status code is " . $response->getStatusCode());
            }

            return (new DomainBuilder())->setDomain($jsonResponse->domain)
                ->setSubscriptionHandle($jsonResponse->subscriptionHandle)->build();
        } catch (ClientException $e) {
            //Guzzle throws client exception on 400 error codes
            $message = $this->getErrorMessageFromResponse($e->getResponse());
            switch($e->getCode()) {
                case 401:
                    throw new InboundApiUnauthorizedException($message);
                case 403:
                    throw new InboundApiForbiddenException($message);
                case 409:
                    throw new InboundApiConflictException($message);
                default:
                    throw new InboundApiInternalServerErrorException($message);
            }
        }
    }

    /**
     * @param $domain
     * @throws InboundApiException
     * @throws InboundApiForbiddenException
     * @throws InboundApiInternalServerErrorException
     * @throws InboundApiNotFoundException
     * @throws InboundApiUnauthorizedException
     */
    public function deprovisionDomain($domain) {
        if(!is_string($domain)) {
            throw new InboundApiException("arguments are not of string");
        }

        $uri = "domains";
        try {
            $response = $this->call('DELETE', "$uri/$domain");
            if($response->getStatusCode() != 204) {
                throw new InboundApiInternalServerErrorException($this->getErrorMessageFromResponse($response));
            }
            return;
        } catch (ClientException $e) {
            $message = $this->getErrorMessageFromResponse($e->getResponse());
            switch ($e->getCode()) {
                case 401:
                    throw new InboundApiUnauthorizedException($message);
                case 403:
                    throw new InboundApiForbiddenException($message);
                case 404:
                    throw new InboundApiNotFoundException($message);
                case 422:
                    throw new InboundApiUnprocessableException($message);
                default:
                    throw new InboundApiInternalServerErrorException($message);
            }
        } catch (\Exception $e) {
            throw new InboundApiException($e->getMessage());
        }
    }

    /**
     * @return array
     * @throws InboundApiConnectException
     * @throws InboundApiInternalServerErrorException
     * @throws InboundApiNotFoundException
     * @throws InboundApiUnauthorizedException
     */
    public function getSubscriptions() {
        $uri = "subscriptions";
        try {
            $response = $this->call('GET', $uri);

            $jsonResponse = json_decode($response->getBody()->getContents());
            $resultSubscriptions = array();
            foreach($jsonResponse as $subscription) {
                $resultLimits = array();
                foreach($subscription->limits as $limit) {
                    $builder = new LimitBuilder();
                    $builder
                        ->setValue($limit->value)
                        ->setFeatureHandle($limit->featureHandle);
                    $resultLimits[] = $builder->build();
                }

                $subscriptionBuilder = (new SubscriptionBuilder())
                    ->setHandle($subscription->handle)
                    ->setActive($subscription->active)
                    ->setLimits($resultLimits);

                if (isset($subscription->activeAccountsCount)) {
                    $subscriptionBuilder->setActiveAccountsCount($subscription->activeAccountsCount);
                }

                if (isset($subscription->plan)) {
                    $subscriptionBuilder->setPlan(
                        (new PlanBuilder())
                            ->deserializeJson($subscription->plan)
                            ->build()
                    );
                }

                $resultSubscriptions[] = $subscriptionBuilder->build();
            }

            return $resultSubscriptions;
        } catch (ClientException $e) {
            $message = $this->getErrorMessageFromResponse($e->getResponse());
            switch ($e->getCode()) {
                case 401:
                    throw new InboundApiUnauthorizedException($message);
                case 404:
                    throw new InboundApiNotFoundException($message);
                default:
                    throw new InboundApiInternalServerErrorException($message);
            }
        }
    }

    public function getDomains($domainNames=null) {
        if ($domainNames && !is_array($domainNames)) {
            $domainNames = [$domainNames];
        }

        $domains = array();
        $total = 0;
        $params=null;

        if (!empty($domainNames)) {
            $params = http_build_query([
                'domains' => implode(',', $domainNames)
            ]);
        }

        try {
            $response = $this->call('GET', "domains?$params");
            $json = json_decode($response->getBody()->getContents());

            $total = $json->total;

            foreach ($json->domains as $domain) {
                $domains[$domain->domain] = (new DomainBuilder())
                    ->setDomain($domain->domain)
                    ->setSubscriptionHandle($domain->subscriptionHandle)
                    ->build();
            }
        } catch (ClientException $e) {
            $message = $this->getErrorMessageFromResponse($e->getResponse());
            switch ($e->getCode()) {
                case 401:
                    throw new InboundApiUnauthorizedException($message, $e->getCode(), $e);
                default:
                    throw new InboundApiInternalServerErrorException($message, $e->getCode(), $e);
            }
        }

        return new GetDomainsResponse($domains, $total);
    }

    /**
     * @param $method
     * @param $uri
     * @param $options
     * @return ResponseInterface
     * @throws InboundApiConnectException
     */
    protected function call($method, $uri, $options=[]) {
        try {
            App::getLogger()->debug("[MailChannels Inbound API] request - method: $method, URI: $uri; options: " . json_encode($options));

            return $this->client->request($method, $uri, $options);
        } catch (ClientException $e) {
            App::getLogger()->debug("[MailChannels Inbound API] exception - method: $method URI: $uri; options: " . json_encode($options));
            App::getLogger()->debug($e);

            throw $e;
        } catch (ConnectException $e) {
            throw new InboundApiConnectException("Couldn't connect to the mailchannels api", $e->getCode(), $e);
        }
    }

    private function getErrorMessageFromResponse($response) {
        $jsonResponse = json_decode($response->getBody()->getContents());
        if($response == null || $jsonResponse == null) {
            return "";
        }

        if(property_exists($jsonResponse, "message")) {
            return $jsonResponse->message;
        }
        return "";
    }

    public function getDownstreamAddresses($domain, $limit=null, $offset=null) {
        $downstreamAddressRecords = array();
        try {
            $response = $this->call('GET', "domains/$domain/downstream-address");
            $json = json_decode($response->getBody()->getContents());
            App::getLogger()->info("response from the API " . json_encode($json));
            foreach ($json->records as $record) {
                $downstreamAddressRecords[] = $downstreamAddressRecord = (new DownstreamAddressBuilder())
                    ->setTarget($record->target)
                    ->setPriority($record->priority)
                    ->setPort($record->port)
                    ->setWeight($record->weight)
                    ->build();
            }
        } catch (ClientException $e) {
            $message = $this->getErrorMessageFromResponse($e->getResponse());
            switch($e->getCode()) {
                case 403:
                    throw new InboundApiUnauthorizedException($message);
                case 404:
                    throw new InboundApiNotFoundException($message);
                default:
                    throw new InboundApiInternalServerErrorException($message);
            }
        }

        return $downstreamAddressRecords;
    }

    public function setDownstreamAddresses($domain, $records)
    {
        if(sizeof($records)>self::MAXIMUM_DOWNSTREAM_ADDRESSES){
            throw new InboundApiException("too many downstream addresses");
        }

        foreach($records as $record){
            if(strlen($record->getTarget())>self::MAXIMUM_TARGET_LENGTH){
                throw new InboundApiException("target longer than maximum length");
            }
        }
        
        $downstreamAddressRecords = array();
        foreach ($records as $record) {
            $downstreamAddressRecords[] = $downstreamAddressRecord = $record->jsonSerialize();
        }

        $requestBody = [
            "records" => $downstreamAddressRecords
        ];

        try {
            $url = "domains/$domain/downstream-address";

            $response = $this->call('PUT', $url, [
                'headers' => [
                    'Content-Type' => 'application/json'
                ],
                'body' => json_encode($requestBody)
            ]);

            if ($response->getStatusCode() != 201) {
                throw new InboundApiInternalServerErrorException($this->getErrorMessageFromResponse($response));
            }

            return null;
        } catch (ClientException $e) {
            $message = $this->getErrorMessageFromResponse($e->getResponse());
            switch($e->getCode()) {
                case 403:
                    throw new InboundApiUnauthorizedException($message);
                case 404:
                    throw new InboundApiConflictException($message);
                default:
                    throw new InboundApiInternalServerErrorException($message);
            }
        }
    }
}