diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml index 33b6064..3f73e33 100644 --- a/config/packages/api_platform.yaml +++ b/config/packages/api_platform.yaml @@ -27,4 +27,17 @@ api_platform: JWT: name: Authorization type: header + exception_to_status: + # The 4 following handlers are registered by default, keep those lines to prevent unexpected side effects + Symfony\Component\Serializer\Exception\ExceptionInterface: 400 # Use a raw status code (recommended) + ApiPlatform\Exception\InvalidArgumentException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST + ApiPlatform\ParameterValidator\Exception\ValidationExceptionInterface: 400 + Doctrine\ORM\OptimisticLockException: 409 + # Validation exception + ApiPlatform\Validator\Exception\ValidationException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_UNPROCESSABLE_ENTITY + + App\Exception\DomainNotFoundException: 404 + App\Exception\MalformedDomainException: 403 + App\Exception\TldNotSupportedException: 403 + App\Exception\UnknownRdapServerException: 403 diff --git a/src/Controller/DomainRefreshController.php b/src/Controller/DomainRefreshController.php index 1aded3d..032de90 100644 --- a/src/Controller/DomainRefreshController.php +++ b/src/Controller/DomainRefreshController.php @@ -60,6 +60,7 @@ class DomainRefreshController extends AbstractController ) { $this->logger->info('It is not necessary to update the domain name', [ 'ldhName' => $idnDomain, + 'updatedAt' => $domain->getUpdatedAt()->format(\DateTimeInterface::ATOM), ]); return $domain; diff --git a/src/Exception/DomainNotFoundException.php b/src/Exception/DomainNotFoundException.php new file mode 100644 index 0000000..5741443 --- /dev/null +++ b/src/Exception/DomainNotFoundException.php @@ -0,0 +1,11 @@ +sender = new Address($mailerSenderEmail, $mailerSenderName); } @@ -95,6 +97,7 @@ final readonly class UpdateDomainsFromWatchlistHandler foreach ($watchList->getDomains()->filter(fn ($domain) => $domain->isToBeUpdated(false, null !== $watchList->getConnector())) as $domain ) { $updatedAt = $domain->getUpdatedAt(); + $deleted = $domain->getDeleted(); try { /* @@ -103,8 +106,10 @@ final readonly class UpdateDomainsFromWatchlistHandler */ $this->RDAPService->registerDomain($domain->getLdhName()); $this->bus->dispatch(new SendDomainEventNotif($watchList->getToken(), $domain->getLdhName(), $updatedAt)); - } catch (NotFoundHttpException) { - if (!$domain->getDeleted()) { + } catch (DomainNotFoundException) { + $newDomain = $this->domainRepository->findOneBy(['ldhName' => $domain->getLdhName()]); + + if (!$deleted && null !== $newDomain && $newDomain->getDeleted()) { $notification = new DomainDeletedNotification($this->sender, $domain); $this->mailer->send($notification->asEmailMessage(new Recipient($watchList->getUser()->getEmail()))->getMessage()); $this->chatNotificationService->sendChatNotification($watchList, $notification); @@ -117,20 +122,10 @@ final readonly class UpdateDomainsFromWatchlistHandler */ $this->bus->dispatch(new OrderDomain($watchList->getToken(), $domain->getLdhName())); } - } catch (\Throwable $e) { + } catch (TldNotSupportedException|UnknownRdapServerException) { /* - * In case of another unknown error, - * the owner of the Watchlist is informed that an error occurred in updating the domain name. + * In this case, the domain name can no longer be updated. Unfortunately, there is nothing more that can be done. */ - $this->logger->error('Update error email is sent to user', [ - 'username' => $watchList->getUser()->getUserIdentifier(), - 'error' => $e, - ]); - $email = (new DomainUpdateErrorNotification($this->sender, $domain)) - ->asEmailMessage(new Recipient($watchList->getUser()->getEmail())); - $this->mailer->send($email->getMessage()); - - throw $e; } } } diff --git a/src/Service/RDAPService.php b/src/Service/RDAPService.php index 006fb93..5b5b163 100644 --- a/src/Service/RDAPService.php +++ b/src/Service/RDAPService.php @@ -19,6 +19,10 @@ use App\Entity\Nameserver; use App\Entity\NameserverEntity; use App\Entity\RdapServer; use App\Entity\Tld; +use App\Exception\DomainNotFoundException; +use App\Exception\MalformedDomainException; +use App\Exception\TldNotSupportedException; +use App\Exception\UnknownRdapServerException; use App\Repository\DomainEntityRepository; use App\Repository\DomainEventRepository; use App\Repository\DomainRepository; @@ -31,17 +35,14 @@ use App\Repository\RdapServerRepository; use App\Repository\TldRepository; use Doctrine\DBAL\LockMode; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Exception\ORMException; +use Doctrine\ORM\OptimisticLockException; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpClient\Exception\ClientException; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Yaml\Yaml; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; -use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; @@ -119,9 +120,16 @@ class RDAPService } /** - * @throws HttpExceptionInterface - * @throws TransportExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DomainNotFoundException * @throws DecodingExceptionInterface + * @throws TldNotSupportedException + * @throws ClientExceptionInterface + * @throws OptimisticLockException + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws MalformedDomainException + * @throws UnknownRdapServerException */ public function registerDomains(array $domains): void { @@ -131,11 +139,16 @@ class RDAPService } /** - * @throws TransportExceptionInterface - * @throws ServerExceptionInterface + * @throws DomainNotFoundException * @throws RedirectionExceptionInterface * @throws DecodingExceptionInterface + * @throws TldNotSupportedException * @throws ClientExceptionInterface + * @throws OptimisticLockException + * @throws TransportExceptionInterface + * @throws MalformedDomainException + * @throws ServerExceptionInterface + * @throws UnknownRdapServerException * @throws \Exception */ public function registerDomain(string $fqdn): Domain @@ -163,7 +176,7 @@ class RDAPService $this->updateDomainStatus($domain, $rdapData); if (in_array('free', $domain->getStatus())) { - throw new NotFoundHttpException("The domain name $idnDomain is not present in the WHOIS database."); + throw DomainNotFoundException::fromDomain($idnDomain); } $domain @@ -185,13 +198,17 @@ class RDAPService return $domain; } + /** + * @throws TldNotSupportedException + * @throws MalformedDomainException + */ public function getTld(string $domain): Tld { if (!str_contains($domain, '.')) { $tldEntity = $this->tldRepository->findOneBy(['tld' => '.']); if (null == $tldEntity) { - throw new NotFoundHttpException("The requested TLD $domain is not yet supported, please try again with another one"); + throw TldNotSupportedException::fromTld($domain); } return $tldEntity; @@ -200,14 +217,14 @@ class RDAPService $lastDotPosition = strrpos($domain, '.'); if (false === $lastDotPosition) { - throw new BadRequestException('Domain must contain at least one dot'); + throw MalformedDomainException::fromDomain($domain); } $tld = self::convertToIdn(substr($domain, $lastDotPosition + 1)); $tldEntity = $this->tldRepository->findOneBy(['tld' => $tld]); if (null === $tldEntity) { - throw new NotFoundHttpException("The requested TLD $tld is not yet supported, please try again with another one"); + throw TldNotSupportedException::fromTld($domain); } return $tldEntity; @@ -218,13 +235,16 @@ class RDAPService return strtolower(idn_to_ascii($fqdn)); } + /** + * @throws UnknownRdapServerException + */ private function fetchRdapServer(Tld $tld): RdapServer { $tldString = $tld->getTld(); $rdapServer = $this->rdapServerRepository->findOneBy(['tld' => $tldString], ['updatedAt' => 'DESC']); if (null === $rdapServer) { - throw new NotFoundHttpException("TLD $tldString : Unable to determine which RDAP server to contact"); + throw UnknownRdapServerException::fromTld($tldString); } return $rdapServer; @@ -292,7 +312,7 @@ class RDAPService $this->em->flush(); } - throw new NotFoundHttpException("The domain name $idnDomain is not present in the WHOIS database."); + throw DomainNotFoundException::fromDomain($idnDomain); } return $e; @@ -771,7 +791,6 @@ class RDAPService } /** - * @throws ORMException * @throws \Exception */ public function updateRDAPServersFromFile(string $fileName): void @@ -890,8 +909,8 @@ class RDAPService * @throws TransportExceptionInterface * @throws ServerExceptionInterface * @throws RedirectionExceptionInterface - * @throws ClientExceptionInterface * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface * @throws \Exception */ public function updateGTldListICANN(): void diff --git a/src/State/AutoRegisterDomainProvider.php b/src/State/AutoRegisterDomainProvider.php index 107e466..87f8051 100644 --- a/src/State/AutoRegisterDomainProvider.php +++ b/src/State/AutoRegisterDomainProvider.php @@ -5,12 +5,12 @@ namespace App\State; use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProviderInterface; use App\Entity\Domain; +use App\Exception\DomainNotFoundException; use App\Service\RDAPService; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\RateLimiter\RateLimiterFactory; @@ -49,7 +49,7 @@ readonly class AutoRegisterDomainProvider implements ProviderInterface try { $domain = $this->RDAPService->registerDomain($ldhName); - } catch (NotFoundHttpException) { + } catch (DomainNotFoundException) { $domain = (new Domain()) ->setLdhName($ldhName) ->setTld($this->RDAPService->getTld($ldhName)) diff --git a/templates/emails/errors/domain_deleted.html.twig b/templates/emails/errors/domain_deleted.html.twig index 5113a06..ff68475 100644 --- a/templates/emails/errors/domain_deleted.html.twig +++ b/templates/emails/errors/domain_deleted.html.twig @@ -1,10 +1,10 @@ -{% extends "../base.html.twig" %} +{% extends "base.html.twig" %} {% set email_color = '#0056b3' %} {% set title = 'Domain Watchdog Alert' %} {% block content %}
Hello,
- We are pleased to inform you that a domain name in your watchlist has been detected as deleted from the WHOIS database.
+ This is to inform you that a domain name in your watchlist has been detected as deleted from the WHOIS database.
Domain name: {{ domain.ldhName }}
Detection Date: {{ domain.updatedAt | date("c") }}