From b99fe856e22cc417714c923935d2a8dc896c1ff9 Mon Sep 17 00:00:00 2001 From: Flavio Heleno Date: Sat, 23 Sep 2023 18:29:06 -0300 Subject: [PATCH] Add a new command "view:domain" for displaying formatted Domain Name information --- bin/console.php | 9 +- .../Commands/View/ViewDomainCommand.php | 129 ++++++++++++++++++ src/Console/DataObjects/Domain/DnsSec.php | 13 +- src/Console/DataObjects/Domain/DomainInfo.php | 18 ++- 4 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 src/Console/Commands/View/ViewDomainCommand.php diff --git a/bin/console.php b/bin/console.php index 412b25a..5a79e01 100755 --- a/bin/console.php +++ b/bin/console.php @@ -13,13 +13,15 @@ } require_once dirname(__DIR__) . '/vendor/autoload.php'; + use Composer\InstalledVersions; use DI\ContainerBuilder; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\CommandLoader\ContainerCommandLoader; use Watchr\Console\Commands\Check\CheckAllCommand; use Watchr\Console\Commands\Check\CheckCertificateCommand; use Watchr\Console\Commands\Check\CheckDomainCommand; -use Symfony\Component\Console\Application; -use Symfony\Component\Console\CommandLoader\ContainerCommandLoader; +use Watchr\Console\Commands\View\ViewDomainCommand; define( '__VERSION__', @@ -52,7 +54,8 @@ [ CheckAllCommand::getDefaultName() => CheckAllCommand::class, CheckCertificateCommand::getDefaultName() => CheckCertificateCommand::class, - CheckDomainCommand::getDefaultName() => CheckDomainCommand::class + CheckDomainCommand::getDefaultName() => CheckDomainCommand::class, + ViewDomainCommand::getDefaultName() => ViewDomainCommand::class ] ) ); diff --git a/src/Console/Commands/View/ViewDomainCommand.php b/src/Console/Commands/View/ViewDomainCommand.php new file mode 100644 index 0000000..888afc3 --- /dev/null +++ b/src/Console/Commands/View/ViewDomainCommand.php @@ -0,0 +1,129 @@ +addOption( + 'json', + 'j', + InputOption::VALUE_NONE, + 'Format the output as a JSON string' + ) + ->addArgument( + 'domain', + InputArgument::REQUIRED, + 'Domain Name to be viewed' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $jsonOutput = (bool)$input->getOption('json'); + $domain = $input->getArgument('domain'); + try { + if ( + strpos($domain, '.') === false || + filter_var($domain, FILTER_VALIDATE_DOMAIN, ['flags' => FILTER_FLAG_HOSTNAME]) === false + ) { + throw new InvalidArgumentException('argument domain contains an invalid domain name'); + } + + $info = $this->domainService->lookup($domain); + if ($info === null) { + throw new RuntimeException('Failed to load domain information'); + } + + if ($jsonOutput === true) { + $output->write(json_encode($info)); + + return Command::SUCCESS; + } + + $now = $this->clock->now(); + + $lines = []; + $lines[] = sprintf('Domain: %s', $info->domainName); + $lines[] = 'Name Servers'; + foreach ($info->nameServers as $nameServer) { + $lines[] = sprintf(' * %s', $nameServer); + } + + $lines[] = sprintf( + 'Creation date: %s (%s)', + $info->creationDate->format(DateTimeInterface::ATOM), + $this->humanReadableInterval($now->diff($info->creationDate)) + ); + $lines[] = sprintf( + 'Expiration date: %s (%s)', + $info->expirationDate->format(DateTimeInterface::ATOM), + $this->humanReadableInterval($now->diff($info->expirationDate)) + ); + $lines[] = sprintf( + 'Last update: %s (%s)', + $info->updatedDate->format(DateTimeInterface::ATOM), + $this->humanReadableInterval($now->diff($info->updatedDate)) + ); + $lines[] = 'EPP Flags'; + foreach ($info->states as $state) { + $lines[] = sprintf(' * %s', $state); + } + + $lines[] = sprintf('Registrar: %s', $info->registrar); + $lines[] = sprintf('DNSSEC: %s', $info->dnssec === null ? 'NO' : 'YES'); + + $output->writeln($lines); + + return Command::SUCCESS; + } catch (Exception $exception) { + if ($jsonOutput === true) { + $out = ['error' => $exception->getMessage()]; + if ($output->isDebug() === true) { + $out['trace'] = $exception->getTrace(); + } + + $output->write(json_encode($out)); + + return Command::FAILURE; + } + + $output->writeln($exception->getMessage()); + if ($output->isDebug() === true) { + $output->writeln($exception->getTraceAsString()); + } + + return Command::FAILURE; + } + } + + public function __construct( + ClockInterface $clock, + DomainService $domainService + ) { + parent::__construct(); + + $this->clock = $clock; + $this->domainService = $domainService; + } +} diff --git a/src/Console/DataObjects/Domain/DnsSec.php b/src/Console/DataObjects/Domain/DnsSec.php index e488c71..38c6e73 100644 --- a/src/Console/DataObjects/Domain/DnsSec.php +++ b/src/Console/DataObjects/Domain/DnsSec.php @@ -3,7 +3,9 @@ namespace Watchr\Console\DataObjects\Domain; -final class DnsSec { +use JsonSerializable; + +final class DnsSec implements JsonSerializable { public readonly int|null $keyTag; public readonly int|null $algorithm; public readonly int|null $digestType; @@ -20,4 +22,13 @@ public function __construct( $this->digestType = $digestType; $this->digest = $digest; } + + public function jsonSerialize(): mixed { + return [ + 'keyTag' => $this->keyTag, + 'algorithm' => $this->algorithm, + 'digestType' => $this->digestType, + 'digest' => $this->digest + ]; + } } diff --git a/src/Console/DataObjects/Domain/DomainInfo.php b/src/Console/DataObjects/Domain/DomainInfo.php index 37c71e4..906c179 100644 --- a/src/Console/DataObjects/Domain/DomainInfo.php +++ b/src/Console/DataObjects/Domain/DomainInfo.php @@ -4,8 +4,9 @@ namespace Watchr\Console\DataObjects\Domain; use DateTimeInterface; +use JsonSerializable; -final class DomainInfo { +final class DomainInfo implements JsonSerializable { public readonly string $domainName; public readonly string $whoisServer; /** @@ -50,4 +51,19 @@ public function __construct( $this->registrar = $registrar; $this->dnssec = $dnssec; } + + public function jsonSerialize(): mixed { + return [ + 'domainName' => $this->domainName, + 'whoisServer' => $this->whoisServer, + 'nameServers' => $this->nameServers, + 'creationDate' => $this->creationDate->format(DateTimeInterface::ATOM), + 'expirationDate' => $this->expirationDate->format(DateTimeInterface::ATOM), + 'updatedDate' => $this->updatedDate->format(DateTimeInterface::ATOM), + 'states' => $this->states, + 'owner' => $this->owner, + 'registrar' => $this->registrar, + 'dnssec' => $this->dnssec + ]; + } }