diff --git a/composer.json b/composer.json index c61483b..40c68f5 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,7 @@ "influxdata/influxdb-client-php": "^3.6", "knpuniversity/oauth2-client-bundle": "^2.18", "lexik/jwt-authentication-bundle": "^3.1", + "metaregistrar/php-epp-client": "^1.0", "nelmio/cors-bundle": "^2.5", "ovh/ovh": "^3.3", "phpdocumentor/reflection-docblock": "^5.4", diff --git a/composer.lock b/composer.lock index 66fee13..926249e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "29ad927d4b30a375b7f6b10bfe160d43", + "content-hash": "a4fba182d42fd845c37ea2a74b65566e", "packages": [ { "name": "api-platform/core", @@ -2471,6 +2471,58 @@ ], "time": "2025-01-06T16:34:57+00:00" }, + { + "name": "metaregistrar/php-epp-client", + "version": "1.0.13", + "source": { + "type": "git", + "url": "https://github.com/metaregistrar/php-epp-client.git", + "reference": "efba35794750fb7e04b3f5f7b904a435f79878ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/metaregistrar/php-epp-client/zipball/efba35794750fb7e04b3f5f7b904a435f79878ea", + "reference": "efba35794750fb7e04b3f5f7b904a435f79878ea", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": "^7|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^7" + }, + "type": "library", + "autoload": { + "classmap": [ + "Protocols/", + "Registries/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ewout de Graaf", + "email": "ewout@metaregistrar.com" + } + ], + "description": "Object-oriented PHP EPP Client", + "homepage": "https://github.com/metaregistrar/php-epp-client", + "keywords": [ + "domains", + "epp", + "xml" + ], + "support": { + "issues": "https://github.com/metaregistrar/php-epp-client/issues", + "source": "https://github.com/metaregistrar/php-epp-client/tree/1.0.13" + }, + "time": "2024-05-16T13:03:04+00:00" + }, { "name": "monolog/monolog", "version": "3.8.1", diff --git a/src/Controller/ConnectorController.php b/src/Controller/ConnectorController.php index 4151b74..08c7e92 100644 --- a/src/Controller/ConnectorController.php +++ b/src/Controller/ConnectorController.php @@ -6,10 +6,8 @@ use App\Config\ConnectorProvider; use App\Entity\Connector; use App\Entity\User; use App\Service\Connector\AbstractProvider; -use DateTimeImmutable; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\EntityManagerInterface; -use Exception; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\DependencyInjection\Attribute\Autowire; @@ -23,13 +21,12 @@ use Symfony\Component\Serializer\SerializerInterface; class ConnectorController extends AbstractController { public function __construct( - private readonly SerializerInterface $serializer, + private readonly SerializerInterface $serializer, private readonly EntityManagerInterface $em, - private readonly LoggerInterface $logger, + private readonly LoggerInterface $logger, #[Autowire(service: 'service_container')] - private readonly ContainerInterface $locator, - ) - { + private readonly ContainerInterface $locator, + ) { } #[Route( @@ -50,7 +47,7 @@ class ConnectorController extends AbstractController } /** - * @throws Exception + * @throws \Exception */ #[Route( path: '/api/connectors', @@ -80,8 +77,8 @@ class ConnectorController extends AbstractController throw new BadRequestHttpException('Provider not found'); } - if ($provider === ConnectorProvider::EPP) { - $directory = sprintf('var/epp-certificates/%s/', $connector->getId()); + if (ConnectorProvider::EPP === $provider) { + $directory = sprintf('../var/epp-certificates/%s/', $connector->getId()); $filesystem = new Filesystem(); $filesystem->mkdir($directory); @@ -91,11 +88,11 @@ class ConnectorController extends AbstractController throw new BadRequestHttpException('EPP certificates are required'); } - $pemPath = $directory . 'certificate.pem'; - $keyPath = $directory . 'certificate.key'; + $pemPath = $directory.'certificate.pem'; + $keyPath = $directory.'certificate.key'; - $filesystem->dumpFile($pemPath, $authData['certificate_pem']); - $filesystem->dumpFile($keyPath, $authData['certificate_key']); + $filesystem->dumpFile($pemPath, urldecode($authData['certificate_pem'])); + $filesystem->dumpFile($keyPath, urldecode($authData['certificate_key'])); $connector->setAuthData([...$authData, 'files' => ['pem' => $pemPath, 'key' => $keyPath]]); } @@ -115,7 +112,7 @@ class ConnectorController extends AbstractController 'username' => $user->getUserIdentifier(), ]); - $connector->setCreatedAt(new DateTimeImmutable('now')); + $connector->setCreatedAt(new \DateTimeImmutable('now')); $this->em->persist($connector); $this->em->flush(); diff --git a/src/Service/Connector/EppClientProvider.php b/src/Service/Connector/EppClientProvider.php index 0f7603d..0b4c857 100644 --- a/src/Service/Connector/EppClientProvider.php +++ b/src/Service/Connector/EppClientProvider.php @@ -3,35 +3,69 @@ namespace App\Service\Connector; use App\Entity\Domain; +use Metaregistrar\EPP\eppCheckDomainRequest; +use Metaregistrar\EPP\eppCheckDomainResponse; +use Metaregistrar\EPP\eppConnection; +use Metaregistrar\EPP\eppContactHandle; +use Metaregistrar\EPP\eppCreateDomainRequest; +use Metaregistrar\EPP\eppDomain; +use Metaregistrar\EPP\eppException; +use Metaregistrar\EPP\eppHelloRequest; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\InvalidArgumentException; - class EppClientProvider extends AbstractProvider implements EppClientProviderInterface { + private eppConnection $eppClient; + public function __construct( CacheItemPoolInterface $cacheItemPool, - ) - { + ) { parent::__construct($cacheItemPool); } protected function verifySpecificAuthData(array $authData): array { // TODO: Create DTO for each authData schema + unset($authData['certificate_pem']); + unset($authData['certificate_key']); return $authData; } protected function assertAuthentication(): void { - //TODO: implementation + $this->connect($this->authData); + $this->eppClient->login(); + + $this->eppClient->request(new eppHelloRequest()); + + $this->eppClient->logout(); + $this->eppClient->disconnect(); } + /** + * @throws eppException + */ public function orderDomain(Domain $domain, bool $dryRun): void { - //TODO: implementation + $this->connect($this->authData); + + $d = new eppDomain($domain->getLdhName()); + $d->setRegistrant($this->authData['domain']['registrant']); + $d->setPeriodUnit($this->authData['domain']['unit']); + $d->setPeriod($this->authData['domain']['period']); + $d->setAuthorisationCode($this->authData['domain']['password']); + + foreach ($this->authData['domain']['contacts'] as $type => $contact) { + $d->addContact(new eppContactHandle($contact, $type)); + } + + $this->eppClient->request(new eppCreateDomainRequest($d)); + + $this->eppClient->logout(); + $this->eppClient->disconnect(); } /** @@ -63,9 +97,55 @@ class EppClientProvider extends AbstractProvider implements EppClientProviderInt return true; } - public function checkDomains(Domain ...$domains): array + /** + * @throws eppException + */ + public function checkDomains(string ...$domains): array { - //TODO : implementation - return []; + $this->connect($this->authData); + $this->eppClient->login(); + + $check = new eppCheckDomainRequest($domains); + + /** @var eppCheckDomainResponse $response */ + $response = $this->eppClient->request($check); + $checkedDomains = $response->getCheckedDomains(); + + $return = array_map( + fn (array $d) => $d['domainname'], + array_filter($checkedDomains, fn (array $d) => true === $d['available']) + ); + + $this->eppClient->logout(); + $this->eppClient->disconnect(); + + return $return; + } + + /** + * @throws eppException + */ + private function connect(array $authData): void + { + $conn = new eppConnection(false, null); + $conn->setHostname($authData['hostname']); + $conn->setVersion($authData['version']); + $conn->setLanguage($authData['language']); + $conn->setPort($authData['port']); + + $conn->setUsername($authData['auth']['username']); + $conn->setPassword($authData['auth']['password']); + $conn->setSslContext(stream_context_create(['ssl' => [ + ...$authData['auth']['ssl'], + 'local_cert' => $authData['files']['pem'], + 'local_pk' => $authData['files']['key'], + ]])); + + $conn->setXpathExtensions($authData['xPathURI']); + $conn->setExtensions($authData['extURI']); + $conn->setServices($authData['objURI']); + + $conn->connect(); + $this->eppClient = $conn; } } diff --git a/src/Service/Connector/EppClientProviderInterface.php b/src/Service/Connector/EppClientProviderInterface.php index 55121c0..e2540ec 100644 --- a/src/Service/Connector/EppClientProviderInterface.php +++ b/src/Service/Connector/EppClientProviderInterface.php @@ -2,9 +2,7 @@ namespace App\Service\Connector; -use App\Entity\Domain; - interface EppClientProviderInterface { - public function checkDomains(Domain ...$domains): array; + public function checkDomains(string ...$domains): array; }