feat: add DNSSEC badge in domain response

This commit is contained in:
Maël Gangloff 2024-12-30 14:31:31 +01:00
parent 51593f31d0
commit 363d7a97f3
No known key found for this signature in database
GPG Key ID: 11FDC81C24A7F629
6 changed files with 87 additions and 22 deletions

View File

@ -11,7 +11,7 @@ import {regionNames} from "../../i18n";
import {getCountryCode} from "../../utils/functions/getCountryCode"; import {getCountryCode} from "../../utils/functions/getCountryCode";
import {eppStatusCodeToColor} from "../../utils/functions/eppStatusCodeToColor"; import {eppStatusCodeToColor} from "../../utils/functions/eppStatusCodeToColor";
import {DomainLifecycleSteps} from "./DomainLifecycleSteps"; import {DomainLifecycleSteps} from "./DomainLifecycleSteps";
import {BankOutlined, SafetyCertificateOutlined} from '@ant-design/icons' import {BankOutlined, KeyOutlined, SafetyCertificateOutlined} from '@ant-design/icons'
export function DomainResult({domain}: { domain: Domain }) { export function DomainResult({domain}: { domain: Domain }) {
@ -68,6 +68,11 @@ export function DomainResult({domain}: { domain: Domain }) {
icon={<BankOutlined icon={<BankOutlined
style={{fontSize: '16px'}}/>}>{t`Registrar Lock`}</Tag> style={{fontSize: '16px'}}/>}>{t`Registrar Lock`}</Tag>
</Tooltip> </Tooltip>
<Tooltip
title={t`DNSSEC secures DNS by adding cryptographic signatures to DNS records, ensuring authenticity and integrity of responses`}>
<Tag bordered={false} color={domain.delegationSigned ? 'green' : 'default'}
icon={<KeyOutlined style={{fontSize: '16px'}}/>}>{t`DNSSEC`}</Tag>
</Tooltip>
</Flex> </Flex>
{domain.status.length > 0 && {domain.status.length > 0 &&
<> <>

View File

@ -60,6 +60,7 @@ export interface Domain {
tld: Tld tld: Tld
deleted: boolean deleted: boolean
updatedAt: string updatedAt: string
delegationSigned: boolean
} }
export interface User { export interface User {

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20241230131605 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add DNSSEC delegation_signed';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE domain ADD delegation_signed BOOLEAN NOT NULL DEFAULT FALSE');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE domain DROP delegation_signed');
}
}

View File

@ -117,6 +117,10 @@ class Domain
#[SerializedName('oldStatus')] #[SerializedName('oldStatus')]
private Collection $domainStatuses; private Collection $domainStatuses;
#[ORM\Column(nullable: false)]
#[Groups(['domain:item'])]
private ?bool $delegationSigned = null;
private const IMPORTANT_EVENTS = [EventAction::Deletion->value, EventAction::Expiration->value]; private const IMPORTANT_EVENTS = [EventAction::Deletion->value, EventAction::Expiration->value];
private const IMPORTANT_STATUS = [ private const IMPORTANT_STATUS = [
'redemption period', 'redemption period',
@ -432,8 +436,22 @@ class Domain
return $this->rdapServer; return $this->rdapServer;
} }
public function setRdapServer(?RdapServer $rdapServer): void public function setRdapServer(?RdapServer $rdapServer): static
{ {
$this->rdapServer = $rdapServer; $this->rdapServer = $rdapServer;
return $this;
}
public function isDelegationSigned(): ?bool
{
return $this->delegationSigned;
}
public function setDelegationSigned(bool $delegationSigned): static
{
$this->delegationSigned = $delegationSigned;
return $this;
} }
} }

View File

@ -142,14 +142,14 @@ readonly class RDAPService
$domain = $this->initNewDomain($idnDomain, $tld); $domain = $this->initNewDomain($idnDomain, $tld);
} }
$domain->setRdapServer($rdapServer);
$this->updateDomainStatus($domain, $rdapData); $this->updateDomainStatus($domain, $rdapData);
if (in_array('free', $domain->getStatus())) { if (in_array('free', $domain->getStatus())) {
throw new NotFoundHttpException('The domain name is not present in the WHOIS database.'); throw new NotFoundHttpException('The domain name is not present in the WHOIS database.');
} }
$domain->setRdapServer($rdapServer)->setDelegationSigned(isset($rdapData['secureDNS']['delegationSigned']) && true === $rdapData['secureDNS']['delegationSigned']);
$this->updateDomainHandle($domain, $rdapData); $this->updateDomainHandle($domain, $rdapData);
$this->updateDomainEvents($domain, $rdapData); $this->updateDomainEvents($domain, $rdapData);
@ -266,7 +266,7 @@ readonly class RDAPService
private function updateDomainStatus(Domain $domain, array $rdapData): void private function updateDomainStatus(Domain $domain, array $rdapData): void
{ {
if (array_key_exists('status', $rdapData)) { if (isset($rdapData['status'])) {
$status = array_unique($rdapData['status']); $status = array_unique($rdapData['status']);
$addedStatus = array_diff($status, $domain->getStatus()); $addedStatus = array_diff($status, $domain->getStatus());
$deletedStatus = array_diff($domain->getStatus(), $status); $deletedStatus = array_diff($domain->getStatus(), $status);
@ -293,7 +293,7 @@ readonly class RDAPService
private function updateDomainHandle(Domain $domain, array $rdapData): void private function updateDomainHandle(Domain $domain, array $rdapData): void
{ {
if (array_key_exists('handle', $rdapData)) { if (isset($rdapData['handle'])) {
$domain->setHandle($rdapData['handle']); $domain->setHandle($rdapData['handle']);
} else { } else {
$this->logger->warning('The domain name {idnDomain} has no handle key.', [ $this->logger->warning('The domain name {idnDomain} has no handle key.', [
@ -312,7 +312,7 @@ readonly class RDAPService
$event->setDeleted(true); $event->setDeleted(true);
} }
if (array_key_exists('events', $rdapData) && is_array($rdapData['events'])) { if (isset($rdapData['events']) && is_array($rdapData['events'])) {
foreach ($rdapData['events'] as $rdapEvent) { foreach ($rdapData['events'] as $rdapEvent) {
if ($rdapEvent['eventAction'] === EventAction::LastUpdateOfRDAPDatabase->value) { if ($rdapEvent['eventAction'] === EventAction::LastUpdateOfRDAPDatabase->value) {
continue; continue;
@ -348,7 +348,7 @@ readonly class RDAPService
$domainEntity->setDeleted(true); $domainEntity->setDeleted(true);
} }
if (array_key_exists('entities', $rdapData) && is_array($rdapData['entities'])) { if (isset($rdapData['entities']) && is_array($rdapData['entities'])) {
foreach ($rdapData['entities'] as $rdapEntity) { foreach ($rdapData['entities'] as $rdapEntity) {
$roles = $this->extractEntityRoles($rdapData['entities'], $rdapEntity); $roles = $this->extractEntityRoles($rdapData['entities'], $rdapEntity);
$entity = $this->registerEntity($rdapEntity, $roles, $domain->getLdhName()); $entity = $this->registerEntity($rdapEntity, $roles, $domain->getLdhName());
@ -422,7 +422,7 @@ readonly class RDAPService
*/ */
private function updateNameserverEntities(Nameserver $nameserver, array $rdapNameserver): void private function updateNameserverEntities(Nameserver $nameserver, array $rdapNameserver): void
{ {
if (!array_key_exists('entities', $rdapNameserver) || !is_array($rdapNameserver['entities'])) { if (!isset($rdapNameserver['entities']) || !is_array($rdapNameserver['entities'])) {
return; return;
} }
@ -456,12 +456,12 @@ readonly class RDAPService
fn ($e) => $e['roles'], fn ($e) => $e['roles'],
array_filter( array_filter(
$entities, $entities,
fn ($e) => array_key_exists('handle', $targetEntity) && array_key_exists('handle', $e) fn ($e) => isset($targetEntity['handle']) && isset($e['handle'])
? $targetEntity['handle'] === $e['handle'] ? $targetEntity['handle'] === $e['handle']
: ( : (
array_key_exists('vcardArray', $targetEntity) && array_key_exists('vcardArray', $e) isset($targetEntity['vcardArray']) && isset($e['vcardArray'])
? $targetEntity['vcardArray'] === $e['vcardArray'] ? $targetEntity['vcardArray'] === $e['vcardArray']
: $targetEntity === $e : $targetEntity === $e
) )
) )
); );
@ -483,9 +483,9 @@ readonly class RDAPService
* If the RDAP server transmits the entity's IANA number, it is used as a priority to identify the entity * If the RDAP server transmits the entity's IANA number, it is used as a priority to identify the entity
*/ */
$isIANAid = false; $isIANAid = false;
if (array_key_exists('publicIds', $rdapEntity)) { if (isset($rdapEntity['publicIds'])) {
foreach ($rdapEntity['publicIds'] as $publicId) { foreach ($rdapEntity['publicIds'] as $publicId) {
if ('IANA Registrar ID' === $publicId['type'] && array_key_exists('identifier', $publicId) && '' !== $publicId['identifier']) { if ('IANA Registrar ID' === $publicId['type'] && isset($publicId['identifier']) && '' !== $publicId['identifier']) {
$rdapEntity['handle'] = $publicId['identifier']; $rdapEntity['handle'] = $publicId['identifier'];
$isIANAid = true; $isIANAid = true;
break; break;
@ -496,7 +496,7 @@ readonly class RDAPService
/* /*
* If there is no number to identify the entity, one is generated from the domain name and the roles associated with this entity * If there is no number to identify the entity, one is generated from the domain name and the roles associated with this entity
*/ */
if (!array_key_exists('handle', $rdapEntity) || '' === $rdapEntity['handle'] || in_array($rdapEntity['handle'], self::ENTITY_HANDLE_BLACKLIST)) { if (!isset($rdapEntity['handle']) || '' === $rdapEntity['handle'] || in_array($rdapEntity['handle'], self::ENTITY_HANDLE_BLACKLIST)) {
sort($roles); sort($roles);
$rdapEntity['handle'] = 'DW-FAKEHANDLE-'.$domain.'-'.implode(',', $roles); $rdapEntity['handle'] = 'DW-FAKEHANDLE-'.$domain.'-'.implode(',', $roles);
@ -519,11 +519,11 @@ readonly class RDAPService
$entity->setHandle($rdapEntity['handle']); $entity->setHandle($rdapEntity['handle']);
if (array_key_exists('remarks', $rdapEntity) && is_array($rdapEntity['remarks']) && !is_numeric($rdapEntity['handle'])) { if (isset($rdapEntity['remarks']) && is_array($rdapEntity['remarks']) && !is_numeric($rdapEntity['handle'])) {
$entity->setRemarks($rdapEntity['remarks']); $entity->setRemarks($rdapEntity['remarks']);
} }
if (array_key_exists('vcardArray', $rdapEntity) && !in_array($rdapEntity['handle'], self::IANA_RESERVED_IDS)) { if (isset($rdapEntity['vcardArray']) && !in_array($rdapEntity['handle'], self::IANA_RESERVED_IDS)) {
if (empty($entity->getJCard())) { if (empty($entity->getJCard())) {
$entity->setJCard($rdapEntity['vcardArray']); $entity->setJCard($rdapEntity['vcardArray']);
} else { } else {
@ -538,7 +538,7 @@ readonly class RDAPService
} }
} }
if ($isIANAid || !array_key_exists('events', $rdapEntity) || in_array($rdapEntity['handle'], self::IANA_RESERVED_IDS)) { if ($isIANAid || !isset($rdapEntity['events']) || in_array($rdapEntity['handle'], self::IANA_RESERVED_IDS)) {
return $entity; return $entity;
} }
@ -620,7 +620,7 @@ readonly class RDAPService
$server $server
->setTld($tldReference) ->setTld($tldReference)
->setUrl($rdapServerUrl) ->setUrl($rdapServerUrl)
->setUpdatedAt(new \DateTimeImmutable(array_key_exists('publication', $dnsRoot) ? $dnsRoot['publication'] : 'now')); ->setUpdatedAt(new \DateTimeImmutable($dnsRoot['publication'] ?? 'now'));
$this->em->persist($server); $this->em->persist($server);
} }

View File

@ -122,15 +122,25 @@ msgstr ""
msgid "Registrar Lock" msgid "Registrar Lock"
msgstr "" msgstr ""
#: assets/components/search/DomainResult.tsx:72
msgid ""
"DNSSEC secures DNS by adding cryptographic signatures to DNS records, "
"ensuring authenticity and integrity of responses"
msgstr ""
#: assets/components/search/DomainResult.tsx:74 #: assets/components/search/DomainResult.tsx:74
msgid "DNSSEC"
msgstr ""
#: assets/components/search/DomainResult.tsx:79
msgid "EPP Status Codes" msgid "EPP Status Codes"
msgstr "" msgstr ""
#: assets/components/search/DomainResult.tsx:83 #: assets/components/search/DomainResult.tsx:88
msgid "Timeline" msgid "Timeline"
msgstr "" msgstr ""
#: assets/components/search/DomainResult.tsx:90 #: assets/components/search/DomainResult.tsx:95
msgid "Entities" msgid "Entities"
msgstr "" msgstr ""