From 5e1c84bb80b56139b09a346c5255b2dae2648da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Sat, 22 Feb 2025 23:36:43 +0100 Subject: [PATCH 1/2] refactor: add DTO class to validate schema --- src/Dto/Connector/AutodnsProviderDto.php | 19 +++++++++ src/Dto/Connector/DefaultProviderDto.php | 17 ++++++++ src/Dto/Connector/GandiProviderDto.php | 13 +++++++ src/Dto/Connector/NameComProviderDto.php | 14 +++++++ src/Dto/Connector/NamecheapProviderDto.php | 14 +++++++ src/Dto/Connector/OvhProviderDto.php | 26 +++++++++++++ src/Service/Connector/AbstractProvider.php | 35 ++++++++++++----- src/Service/Connector/AutodnsProvider.php | 41 +++++++------------- src/Service/Connector/GandiProvider.php | 16 ++++++-- src/Service/Connector/NameComProvider.php | 31 +++++---------- src/Service/Connector/NamecheapProvider.php | 11 +++++- src/Service/Connector/OvhProvider.php | 43 ++++++--------------- 12 files changed, 186 insertions(+), 94 deletions(-) create mode 100644 src/Dto/Connector/AutodnsProviderDto.php create mode 100644 src/Dto/Connector/DefaultProviderDto.php create mode 100644 src/Dto/Connector/GandiProviderDto.php create mode 100644 src/Dto/Connector/NameComProviderDto.php create mode 100644 src/Dto/Connector/NamecheapProviderDto.php create mode 100644 src/Dto/Connector/OvhProviderDto.php diff --git a/src/Dto/Connector/AutodnsProviderDto.php b/src/Dto/Connector/AutodnsProviderDto.php new file mode 100644 index 0000000..1f315b0 --- /dev/null +++ b/src/Dto/Connector/AutodnsProviderDto.php @@ -0,0 +1,19 @@ +serializer->denormalize($this->verifyLegalAuthData($authData), $this->dtoClass); + $violations = $this->validator->validate($data); + + if ($violations->count()) { + throw new BadRequestHttpException(implode('\n', array_map(fn (ConstraintViolationInterface $v) => $v->getPropertyPath().': '.$v->getMessage(), iterator_to_array($violations)))); + } + return [ - ...$this->verifySpecificAuthData($this->verifyLegalAuthData($authData)), + ...$this->serializer->normalize($data), 'acceptConditions' => $authData['acceptConditions'], 'ownerLegalAge' => $authData['ownerLegalAge'], 'waiveRetractationPeriod' => $authData['waiveRetractationPeriod'], ]; } - /** - * @param array $authData raw authentication data as supplied by the user - * - * @return array specific authentication data - */ - abstract protected function verifySpecificAuthData(array $authData): array; - /** * @param array $authData raw authentication data as supplied by the user * @@ -117,6 +133,7 @@ abstract class AbstractProvider } /** + * @throws ExceptionInterface * @throws \Exception */ public function authenticate(array $authData): void diff --git a/src/Service/Connector/AutodnsProvider.php b/src/Service/Connector/AutodnsProvider.php index 0e2b72e..35039c0 100644 --- a/src/Service/Connector/AutodnsProvider.php +++ b/src/Service/Connector/AutodnsProvider.php @@ -2,6 +2,7 @@ namespace App\Service\Connector; +use App\Dto\Connector\AutodnsProviderDto; use App\Entity\Domain; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; @@ -10,6 +11,9 @@ use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use Symfony\Component\HttpClient\HttpOptions; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; @@ -20,9 +24,15 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; #[Autoconfigure(public: true)] class AutodnsProvider extends AbstractProvider { - public function __construct(CacheItemPoolInterface $cacheItemPool, private readonly HttpClientInterface $client) - { - parent::__construct($cacheItemPool); + protected string $dtoClass = AutodnsProviderDto::class; + + public function __construct( + CacheItemPoolInterface $cacheItemPool, + DenormalizerInterface&NormalizerInterface $serializer, + private readonly HttpClientInterface $client, + ValidatorInterface $validator, + ) { + parent::__construct($cacheItemPool, $serializer, $validator); } private const BASE_URL = 'https://api.autodns.com'; @@ -167,31 +177,6 @@ class AutodnsProvider extends AbstractProvider } } - public function verifySpecificAuthData(array $authData): array - { - $username = $authData['username']; - $password = $authData['password']; - - if (empty($authData['context'])) { - $authData['context'] = 4; - } - - if ( - !is_string($username) || empty($username) - || !is_string($password) || empty($password) - || true !== $authData['ownerConfirm'] - ) { - throw new BadRequestHttpException('Bad authData schema'); - } - - return [ - 'username' => $authData['username'], - 'password' => $authData['password'], - 'ownerConfirm' => $authData['ownerConfirm'], - 'context' => $authData['context'], - ]; - } - public function isSupported(Domain ...$domainList): bool { return true; diff --git a/src/Service/Connector/GandiProvider.php b/src/Service/Connector/GandiProvider.php index 346d8ad..997e908 100644 --- a/src/Service/Connector/GandiProvider.php +++ b/src/Service/Connector/GandiProvider.php @@ -2,6 +2,7 @@ namespace App\Service\Connector; +use App\Dto\Connector\GandiProviderDto; use App\Entity\Domain; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; @@ -10,6 +11,9 @@ use Symfony\Component\HttpClient\HttpOptions; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\HttpException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; @@ -20,11 +24,17 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; #[Autoconfigure(public: true)] class GandiProvider extends AbstractProvider { + protected string $dtoClass = GandiProviderDto::class; + private const BASE_URL = 'https://api.gandi.net'; - public function __construct(CacheItemPoolInterface $cacheItemPool, private readonly HttpClientInterface $client) - { - parent::__construct($cacheItemPool); + public function __construct( + CacheItemPoolInterface $cacheItemPool, + private readonly HttpClientInterface $client, + DenormalizerInterface&NormalizerInterface $serializer, + ValidatorInterface $validator, + ) { + parent::__construct($cacheItemPool, $serializer, $validator); } /** diff --git a/src/Service/Connector/NameComProvider.php b/src/Service/Connector/NameComProvider.php index f751440..9329146 100644 --- a/src/Service/Connector/NameComProvider.php +++ b/src/Service/Connector/NameComProvider.php @@ -11,6 +11,9 @@ use Symfony\Component\HttpClient\HttpOptions; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -18,11 +21,15 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; #[Autoconfigure(public: true)] class NameComProvider extends AbstractProvider { + protected string $dtoClass = NameComProvider::class; + public function __construct(CacheItemPoolInterface $cacheItemPool, private readonly HttpClientInterface $client, - private readonly KernelInterface $kernel) - { - parent::__construct($cacheItemPool); + private readonly KernelInterface $kernel, + DenormalizerInterface&NormalizerInterface $serializer, + ValidatorInterface $validator, + ) { + parent::__construct($cacheItemPool, $serializer, $validator); } private const BASE_URL = 'https://api.name.com'; @@ -65,24 +72,6 @@ class NameComProvider extends AbstractProvider )->toArray(); } - public function verifySpecificAuthData(array $authData): array - { - $username = $authData['username']; - $token = $authData['token']; - - if ( - !is_string($username) || empty($username) - || !is_string($token) || empty($token) - ) { - throw new BadRequestHttpException('Bad authData schema'); - } - - return [ - 'username' => $authData['username'], - 'token' => $authData['token'], - ]; - } - public function isSupported(Domain ...$domainList): bool { return true; diff --git a/src/Service/Connector/NamecheapProvider.php b/src/Service/Connector/NamecheapProvider.php index 836ffcb..ed01223 100644 --- a/src/Service/Connector/NamecheapProvider.php +++ b/src/Service/Connector/NamecheapProvider.php @@ -2,12 +2,16 @@ namespace App\Service\Connector; +use App\Dto\Connector\NamecheapProviderDto; use App\Entity\Domain; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\InvalidArgumentException; use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; @@ -17,16 +21,19 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; #[Autoconfigure(public: true)] class NamecheapProvider extends AbstractProvider { - public const BASE_URL = 'https://api.namecheap.com/xml.response'; + protected string $dtoClass = NamecheapProviderDto::class; + public const BASE_URL = 'https://api.namecheap.com/xml.response'; public const SANDBOX_BASE_URL = 'https://api.sandbox.namecheap.com/xml.response'; public function __construct( CacheItemPoolInterface $cacheItemPool, private readonly HttpClientInterface $client, private readonly string $outgoingIp, + DenormalizerInterface&NormalizerInterface $serializer, + ValidatorInterface $validator, ) { - parent::__construct($cacheItemPool); + parent::__construct($cacheItemPool, $serializer, $validator); } /** diff --git a/src/Service/Connector/OvhProvider.php b/src/Service/Connector/OvhProvider.php index 4392d0d..d47c91b 100644 --- a/src/Service/Connector/OvhProvider.php +++ b/src/Service/Connector/OvhProvider.php @@ -2,6 +2,7 @@ namespace App\Service\Connector; +use App\Dto\Connector\OvhProviderDto; use App\Entity\Domain; use GuzzleHttp\Exception\ClientException; use Ovh\Api; @@ -11,10 +12,15 @@ use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\InvalidArgumentException; use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Validator\Validator\ValidatorInterface; #[Autoconfigure(public: true)] class OvhProvider extends AbstractProvider { + protected string $dtoClass = OvhProviderDto::class; + public const REQUIRED_ROUTES = [ [ 'method' => 'GET', @@ -42,9 +48,12 @@ class OvhProvider extends AbstractProvider ], ]; - public function __construct(CacheItemPoolInterface $cacheItemPool) - { - parent::__construct($cacheItemPool); + public function __construct( + CacheItemPoolInterface $cacheItemPool, + DenormalizerInterface&NormalizerInterface $serializer, + ValidatorInterface $validator, + ) { + parent::__construct($cacheItemPool, $serializer, $validator); } /** @@ -128,34 +137,6 @@ class OvhProvider extends AbstractProvider ]); } - /** - * @throws \Exception - */ - public function verifySpecificAuthData(array $authData): array - { - foreach ([ - 'appKey', - 'appSecret', - 'apiEndpoint', - 'consumerKey', - 'ovhSubsidiary', - 'pricingMode', - ] as $key) { - if (empty($authData[$key]) || !is_string($authData[$key])) { - throw new BadRequestHttpException("Bad authData schema: missing or invalid '$key'"); - } - } - - return [ - 'appKey' => $authData['appKey'], - 'appSecret' => $authData['appSecret'], - 'apiEndpoint' => $authData['apiEndpoint'], - 'consumerKey' => $authData['consumerKey'], - 'ovhSubsidiary' => $authData['ovhSubsidiary'], - 'pricingMode' => $authData['pricingMode'], - ]; - } - protected function assertAuthentication(): void { $conn = new Api( From d2118ea7fd876bcfd6aac57880bd5faf16195b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Sat, 22 Feb 2025 23:50:58 +0100 Subject: [PATCH 2/2] chore: remove unused functions --- src/Service/Connector/GandiProvider.php | 21 --------------------- src/Service/Connector/NamecheapProvider.php | 14 -------------- 2 files changed, 35 deletions(-) diff --git a/src/Service/Connector/GandiProvider.php b/src/Service/Connector/GandiProvider.php index 997e908..d6144c5 100644 --- a/src/Service/Connector/GandiProvider.php +++ b/src/Service/Connector/GandiProvider.php @@ -94,27 +94,6 @@ class GandiProvider extends AbstractProvider } } - public function verifySpecificAuthData(array $authData): array - { - $token = $authData['token']; - - if (!is_string($token) || empty($token) - || (array_key_exists('sharingId', $authData) && !is_string($authData['sharingId'])) - ) { - throw new BadRequestHttpException('Bad authData schema'); - } - - $authDataReturned = [ - 'token' => $token, - ]; - - if (array_key_exists('sharingId', $authData)) { - $authDataReturned['sharingId'] = $authData['sharingId']; - } - - return $authDataReturned; - } - /** * @throws TransportExceptionInterface */ diff --git a/src/Service/Connector/NamecheapProvider.php b/src/Service/Connector/NamecheapProvider.php index ed01223..4b542dd 100644 --- a/src/Service/Connector/NamecheapProvider.php +++ b/src/Service/Connector/NamecheapProvider.php @@ -107,20 +107,6 @@ class NamecheapProvider extends AbstractProvider return $data->CommandResponse; } - public function verifySpecificAuthData(array $authData): array - { - foreach (['ApiUser', 'ApiKey'] as $key) { - if (empty($authData[$key]) || !is_string($authData[$key])) { - throw new BadRequestHttpException("Bad authData schema: missing or invalid '$key'"); - } - } - - return [ - 'ApiUser' => $authData['ApiUser'], - 'ApiKey' => $authData['ApiKey'], - ]; - } - /** * @throws TransportExceptionInterface * @throws ServerExceptionInterface