From 47aa081925e62174f01a5770d59030ccce20a4e3 Mon Sep 17 00:00:00 2001 From: Flavio Heleno Date: Sat, 23 Sep 2023 17:52:40 -0300 Subject: [PATCH] Add support for RDAP Closes #5 --- composer.json | 2 + composer.lock | 498 ++++++++++++++++-- config/dependencies.php | 4 + .../Check/CheckCertificateCommand.php | 4 +- .../Commands/Check/CheckDomainCommand.php | 22 +- src/Console/DataObjects/Domain/DnsSec.php | 23 + src/Console/DataObjects/Domain/DomainInfo.php | 53 ++ src/Console/Services/DomainService.php | 149 ++++++ src/Console/Traits/DateUtilsTrait.php | 42 +- 9 files changed, 736 insertions(+), 61 deletions(-) create mode 100644 src/Console/DataObjects/Domain/DnsSec.php create mode 100644 src/Console/DataObjects/Domain/DomainInfo.php create mode 100644 src/Console/Services/DomainService.php diff --git a/composer.json b/composer.json index 3dd0518..01ca9eb 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,9 @@ "ext-filter": "*", "ext-openssl": "*", "acmephp/ssl": "^2.1", + "guzzlehttp/guzzle": "^7.8", "io-developer/php-whois": "^4.1", + "juanparati/rdap-lib": "^2.0", "league/config": "^1.2", "mlocati/ocsp": "^1.1", "php-di/php-di": "^7.0", diff --git a/composer.lock b/composer.lock index 48ae944..bbacb8a 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": "c0b1baa7dfe81fd2f58745c4d40cb0ba", + "content-hash": "29a91abdbbaaba8b3d8b4191df1cc0dd", "packages": [ { "name": "acmephp/ssl", @@ -142,6 +142,331 @@ }, "time": "2022-10-27T11:44:00+00:00" }, + { + "name": "guzzlehttp/guzzle", + "version": "7.8.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1110f66a6530a40fe7aea0378fe608ee2b2248f9", + "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.1", + "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "ext-curl": "*", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.8.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2023-08-27T10:20:53+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d", + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2023-08-03T15:11:55+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.6.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-08-27T10:13:57+00:00" + }, { "name": "io-developer/php-whois", "version": "4.1.10", @@ -204,6 +529,53 @@ }, "time": "2023-01-25T14:42:45+00:00" }, + { + "name": "juanparati/rdap-lib", + "version": "2.1", + "source": { + "type": "git", + "url": "https://github.com/juanparati/RDAPLib.git", + "reference": "c926d29ef038027d7ae05f48a55b7e1d95639dfe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/juanparati/RDAPLib/zipball/c926d29ef038027d7ae05f48a55b7e1d95639dfe", + "reference": "c926d29ef038027d7ae05f48a55b7e1d95639dfe", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.4", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.3", + "phpunit/phpunit": "~9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Juanparati\\RDAPLib\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Juan Lago", + "email": "juanparati@gmail.com" + } + ], + "description": "A PHP RDAP client library", + "support": { + "issues": "https://github.com/juanparati/RDAPLib/issues", + "source": "https://github.com/juanparati/RDAPLib/tree/2.1" + }, + "time": "2021-06-22T12:04:42+00:00" + }, { "name": "laravel/serializable-closure", "version": "v1.3.1", @@ -479,16 +851,16 @@ }, { "name": "nette/utils", - "version": "v4.0.1", + "version": "v4.0.2", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "9124157137da01b1f5a5a22d6486cb975f26db7e" + "reference": "cead6637226456b35e1175cc53797dd585d85545" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/9124157137da01b1f5a5a22d6486cb975f26db7e", - "reference": "9124157137da01b1f5a5a22d6486cb975f26db7e", + "url": "https://api.github.com/repos/nette/utils/zipball/cead6637226456b35e1175cc53797dd585d85545", + "reference": "cead6637226456b35e1175cc53797dd585d85545", "shasum": "" }, "require": { @@ -510,8 +882,7 @@ "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", "ext-json": "to use Nette\\Utils\\Json", "ext-mbstring": "to use Strings::lower() etc...", - "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", - "ext-xml": "to use Strings::length() etc. when mbstring is not available" + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" }, "type": "library", "extra": { @@ -560,9 +931,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.1" + "source": "https://github.com/nette/utils/tree/v4.0.2" }, - "time": "2023-07-30T15:42:21+00:00" + "time": "2023-09-19T11:58:07+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -1071,16 +1442,16 @@ }, { "name": "psr/http-client", - "version": "1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/php-fig/http-client.git", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", "shasum": "" }, "require": { @@ -1117,9 +1488,9 @@ "psr-18" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/1.0.2" + "source": "https://github.com/php-fig/http-client" }, - "time": "2023-04-10T20:12:12+00:00" + "time": "2023-09-23T14:17:50+00:00" }, { "name": "psr/http-factory", @@ -1229,6 +1600,50 @@ }, "time": "2023-04-04T09:54:51+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "symfony/clock", "version": "v6.3.4", @@ -2465,16 +2880,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.34", + "version": "1.10.35", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "7f806b6f1403e6914c778140e2ba07c293cb4901" + "reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/7f806b6f1403e6914c778140e2ba07c293cb4901", - "reference": "7f806b6f1403e6914c778140e2ba07c293cb4901", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e730e5facb75ffe09dfb229795e8c01a459f26c3", + "reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3", "shasum": "" }, "require": { @@ -2523,20 +2938,20 @@ "type": "tidelift" } ], - "time": "2023-09-13T09:49:47+00:00" + "time": "2023-09-19T15:27:56+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "10.1.5", + "version": "10.1.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "1df504e42a88044c27a90136910f0b3fe9e91939" + "reference": "56f33548fe522c8d82da7ff3824b42829d324364" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1df504e42a88044c27a90136910f0b3fe9e91939", - "reference": "1df504e42a88044c27a90136910f0b3fe9e91939", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/56f33548fe522c8d82da7ff3824b42829d324364", + "reference": "56f33548fe522c8d82da7ff3824b42829d324364", "shasum": "" }, "require": { @@ -2593,7 +3008,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.5" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.6" }, "funding": [ { @@ -2601,7 +3016,7 @@ "type": "github" } ], - "time": "2023-09-12T14:37:22+00:00" + "time": "2023-09-19T04:59:03+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2848,16 +3263,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.3.4", + "version": "10.3.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b8d59476f19115c9774b3b447f78131781c6c32b" + "reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b8d59476f19115c9774b3b447f78131781c6c32b", - "reference": "b8d59476f19115c9774b3b447f78131781c6c32b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/747c3b2038f1139e3dcd9886a3f5a948648b7503", + "reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503", "shasum": "" }, "require": { @@ -2881,7 +3296,7 @@ "sebastian/comparator": "^5.0", "sebastian/diff": "^5.0", "sebastian/environment": "^6.0", - "sebastian/exporter": "^5.0", + "sebastian/exporter": "^5.1", "sebastian/global-state": "^6.0.1", "sebastian/object-enumerator": "^5.0", "sebastian/recursion-context": "^5.0", @@ -2929,7 +3344,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.4" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.5" }, "funding": [ { @@ -2945,7 +3360,7 @@ "type": "tidelift" } ], - "time": "2023-09-12T14:42:28+00:00" + "time": "2023-09-19T05:42:37+00:00" }, { "name": "psy/psysh", @@ -3033,12 +3448,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "a4a221e6b171fe5eadf48e21ad8247304738bcd5" + "reference": "898c7f218667877a7e6e47f467518608c9a82072" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/a4a221e6b171fe5eadf48e21ad8247304738bcd5", - "reference": "a4a221e6b171fe5eadf48e21ad8247304738bcd5", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/898c7f218667877a7e6e47f467518608c9a82072", + "reference": "898c7f218667877a7e6e47f467518608c9a82072", "shasum": "" }, "conflict": { @@ -3221,7 +3636,7 @@ "getkirby/panel": "<2.5.14", "getkirby/starterkit": "<=3.7.0.2", "gilacms/gila": "<=1.11.4", - "gleez/cms": "<=1.2", + "gleez/cms": "<=1.2|==2", "globalpayments/php-sdk": "<2", "gogentooss/samlbase": "<1.2.7", "google/protobuf": "<3.15", @@ -3258,7 +3673,7 @@ "in2code/ipandlanguageredirect": "<5.1.2", "in2code/lux": "<17.6.1|>=18,<24.0.2", "innologi/typo3-appointments": "<2.0.6", - "intelliants/subrion": "<=4.2.1", + "intelliants/subrion": "<4.2.2", "islandora/islandora": ">=2,<2.4.1", "ivankristianto/phpwhois": "<=4.3", "jackalope/jackalope-doctrine-dbal": "<1.7.4", @@ -3266,6 +3681,7 @@ "james-heinrich/phpthumb": "<1.7.12", "jasig/phpcas": "<1.3.3", "jcbrand/converse.js": "<3.3.3", + "joomla/application": "<1.0.13", "joomla/archive": "<1.1.12|>=2,<2.0.1", "joomla/filesystem": "<1.6.2|>=2,<2.0.1", "joomla/filter": "<1.4.4|>=2,<2.0.1", @@ -3343,6 +3759,7 @@ "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", + "neos/neos-ui": "<=8.3.3", "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", @@ -3499,7 +3916,6 @@ "stormpath/sdk": "<9.9.99", "studio-42/elfinder": "<2.1.62", "subhh/libconnect": "<7.0.8|>=8,<8.1", - "subrion/cms": "<=4.2.1", "sukohi/surpass": "<1", "sulu/sulu": "<1.6.44|>=2,<2.2.18|>=2.3,<2.3.8|==2.4.0.0-RC1|>=2.5,<2.5.10", "sumocoders/framework-user-bundle": "<1.4", @@ -3569,7 +3985,7 @@ "truckersmp/phpwhois": "<=4.3.1", "ttskch/pagination-service-provider": "<1", "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", - "typo3/cms": "<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", + "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/cms-core": "<8.7.51|>=9,<9.5.42|>=10,<10.4.39|>=11,<11.5.30|>=12,<12.4.4", "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", @@ -3694,7 +4110,7 @@ "type": "tidelift" } ], - "time": "2023-09-15T19:04:11+00:00" + "time": "2023-09-22T22:04:11+00:00" }, { "name": "sebastian/cli-parser", diff --git a/config/dependencies.php b/config/dependencies.php index 666789b..a75e231 100644 --- a/config/dependencies.php +++ b/config/dependencies.php @@ -5,6 +5,7 @@ use DI\ContainerBuilder; use Iodev\Whois\Factory; use Iodev\Whois\Whois; +use Juanparati\RDAPLib\RDAPClient; use Ocsp\CertificateInfo; use Ocsp\CertificateLoader; use Ocsp\Ocsp; @@ -30,6 +31,9 @@ Ocsp::class => static function (ContainerInterface $container): Ocsp { return new Ocsp(); }, + RDAPClient::class => static function (ContainerInterface $container): RDAPClient { + return new RDAPClient(['domain' => 'https://rdap.org/domain/']); + }, Whois::class => static function (ContainerInterface $container): Whois { return Factory::get()->createWhois(); } diff --git a/src/Console/Commands/Check/CheckCertificateCommand.php b/src/Console/Commands/Check/CheckCertificateCommand.php index 1876925..a17c6ca 100644 --- a/src/Console/Commands/Check/CheckCertificateCommand.php +++ b/src/Console/Commands/Check/CheckCertificateCommand.php @@ -262,7 +262,7 @@ static function (Certificate|null $issuer, string $certificate): Certificate { $errors[] = sprintf( 'Certificate for domain "%s" expired %s ago', $domain, - $this->timeAgo($interval) + $this->humanReadableInterval($interval) ); if ($failFast === true) { @@ -485,7 +485,7 @@ static function (Certificate|null $issuer, string $certificate): Certificate { $output->writeln( sprintf( 'OCSP Revocation list last update: %s (%s)', - $this->timeAgo($interval), + $this->humanReadableInterval($interval), $response->getThisUpdate()->format(DateTimeInterface::ATOM) ), OutputInterface::VERBOSITY_DEBUG diff --git a/src/Console/Commands/Check/CheckDomainCommand.php b/src/Console/Commands/Check/CheckDomainCommand.php index ec60a6d..30d693d 100644 --- a/src/Console/Commands/Check/CheckDomainCommand.php +++ b/src/Console/Commands/Check/CheckDomainCommand.php @@ -3,10 +3,8 @@ namespace Watchr\Console\Commands\Check; -use DateTimeImmutable; use DateTimeInterface; use Exception; -use Iodev\Whois\Whois; use Psr\Clock\ClockInterface; use RuntimeException; use Symfony\Component\Console\Attribute\AsCommand; @@ -16,6 +14,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Watchr\Console\Services\DomainService; use Watchr\Console\Traits\DateUtilsTrait; use Watchr\Console\Traits\ErrorPrinterTrait; @@ -25,7 +24,7 @@ final class CheckDomainCommand extends Command { use ErrorPrinterTrait; private ClockInterface $clock; - private Whois $whois; + private DomainService $domainService; protected function configure(): void { $this @@ -143,13 +142,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); try { - $info = $this->whois->loadDomainInfo($domain); + $info = $this->domainService->lookup($domain); if ($info === null) { throw new RuntimeException('Failed to load domain information'); } if ($checks['expirationDate'] === true) { - if ($info->expirationDate === 0) { + if ($info->expirationDate === null) { $errors[] = sprintf( 'Failed to retrieve the expiration date for domain "%s"', $domain @@ -160,22 +159,21 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - $expiresAt = (new DateTimeImmutable())->setTimestamp($info->expirationDate); $output->writeln( sprintf( 'Domain expiration date: %s (%d)', - $expiresAt->format(DateTimeInterface::ATOM), - $info->expirationDate + $info->expirationDate->format(DateTimeInterface::ATOM), + $info->expirationDate->getTimestamp() ), OutputInterface::VERBOSITY_DEBUG ); - $interval = $now->diff($expiresAt); + $interval = $now->diff($info->expirationDate); if ($interval->days <= 0) { $errors[] = sprintf( 'Domain "%s" expired %s ago', $domain, - $this->timeAgo($interval) + $this->humanReadableInterval($interval) ); if ($failFast === true) { @@ -312,11 +310,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int public function __construct( ClockInterface $clock, - Whois $whois + DomainService $domainService ) { parent::__construct(); $this->clock = $clock; - $this->whois = $whois; + $this->domainService = $domainService; } } diff --git a/src/Console/DataObjects/Domain/DnsSec.php b/src/Console/DataObjects/Domain/DnsSec.php new file mode 100644 index 0000000..e488c71 --- /dev/null +++ b/src/Console/DataObjects/Domain/DnsSec.php @@ -0,0 +1,23 @@ +keyTag = $keyTag; + $this->algorithm = $algorithm; + $this->digestType = $digestType; + $this->digest = $digest; + } +} diff --git a/src/Console/DataObjects/Domain/DomainInfo.php b/src/Console/DataObjects/Domain/DomainInfo.php new file mode 100644 index 0000000..37c71e4 --- /dev/null +++ b/src/Console/DataObjects/Domain/DomainInfo.php @@ -0,0 +1,53 @@ +domainName = $domainName; + $this->whoisServer = $whoisServer; + $this->nameServers = $nameServers; + $this->creationDate = $creationDate; + $this->expirationDate = $expirationDate; + $this->updatedDate = $updatedDate; + $this->states = $states; + $this->owner = $owner; + $this->registrar = $registrar; + $this->dnssec = $dnssec; + } +} diff --git a/src/Console/Services/DomainService.php b/src/Console/Services/DomainService.php new file mode 100644 index 0000000..121350f --- /dev/null +++ b/src/Console/Services/DomainService.php @@ -0,0 +1,149 @@ +rdapClient->domainLookup($domain, RDAPClient::ARRAY_OUTPUT); + if ($info === null) { + return null; + } + + $dnsSec = null; + if ($info['secureDNS']['delegationSigned'] === true) { + $dnsSec = new DnsSec( + $info['secureDNS']['dsData'][0]['keyTag'] ?? + $info['secureDNS']['dsData'][0]['keytag'] ?? + null, + $info['secureDNS']['dsData'][0]['algorithm'] ?? null, + $info['secureDNS']['dsData'][0]['digestType'] ?? + $info['secureDNS']['dsData'][0]['digesttype'] ?? + null, + $info['secureDNS']['dsData'][0]['digest'] ?? null + ); + } + + $events = array_reduce( + $info['events'], + static function (array $carry, array $entry): array { + $carry[$entry['eventAction']] = new DateTimeImmutable($entry['eventDate']); + + return $carry; + }, + [] + ); + + $registrar = array_filter( + $info['entities'], + static function (array $entry): bool { + return in_array('registrar', $entry['roles'], true); + } + ); + + $registrar = $registrar[0]['vcardArray'][1][1][3] ?? ''; + + return new DomainInfo( + $domain, + 'https://rdap.verisign.com/com/v1/domain/', + array_reduce( + array_filter( + $info['nameservers'], + static function (array $entry): bool { + return $entry['objectClassName'] === 'nameserver'; + } + ), + static function (array $carry, array $entry): array { + $carry[] = strtolower($entry['ldhName']); + + return $carry; + }, + [] + ), + $events['registration'], + $events['expiration'], + $events['last changed'], + array_map( + static function (string $entry): string { + return str_replace(' ', '', $entry); + }, + $info['status'] + ), + '', + $registrar, + $dnsSec + ); + } catch (Exception $exception) { + // TODO: add $exception to logging + return null; + } + } + + private function whoisLookup(string $domain): DomainInfo|null { + $info = $this->whois->loadDomainInfo($domain); + if ($info === null) { + return null; + } + + return new DomainInfo( + $domain, + $info->whoisServer, + $info->nameServers, + (new DateTimeImmutable())->setTimestamp($info->creationDate), + (new DateTimeImmutable())->setTimestamp($info->expirationDate), + (new DateTimeImmutable())->setTimestamp($info->updatedDate), + $info->states, + $info->owner, + $info->registrar, + $info->dnssec === 'signedDelegation' ? new DnsSec() : null + ); + } + + public function __construct(RDAPClient $rdapClient, Whois $whois) { + $this->rdapClient = $rdapClient; + $this->whois = $whois; + } + + public function lookup(string $domain): DomainInfo { + $domainInfo = $this->rdapLookup($domain); + if ($domainInfo === null) { + $domainInfo = $this->whoisLookup($domain); + } + + if ($domainInfo === null) { + throw new RuntimeException('Failed to lookup domain'); + } + + return $domainInfo; + } +} diff --git a/src/Console/Traits/DateUtilsTrait.php b/src/Console/Traits/DateUtilsTrait.php index f9ade67..27ca089 100644 --- a/src/Console/Traits/DateUtilsTrait.php +++ b/src/Console/Traits/DateUtilsTrait.php @@ -6,29 +6,59 @@ use DateInterval; trait DateUtilsTrait { - private function timeAgo(DateInterval $interval): string { + private function humanReadableInterval(DateInterval $interval): string { + $format = '%d %s ago'; + if ($interval->invert === 0) { + $format = 'in %d %s'; + } + if ($interval->y > 0) { - return $interval->y === 1 ? '1 year ago' : $interval->y . ' years ago'; + return sprintf( + $format, + $interval->y, + $interval->y === 1 ? 'year' : 'years' + ); } if ($interval->m > 0) { - return $interval->m === 1 ? '1 month ago' : $interval->m . ' months ago'; + return sprintf( + $format, + $interval->m, + $interval->m === 1 ? 'month' : 'months' + ); } if ($interval->d > 0) { - return $interval->d === 1 ? '1 day ago' : $interval->d . ' days ago'; + return sprintf( + $format, + $interval->d, + $interval->d === 1 ? 'day' : 'days' + ); } if ($interval->h > 0) { - return $interval->h === 1 ? '1 hour ago' : $interval->h . ' hours ago'; + return sprintf( + $format, + $interval->h, + $interval->h === 1 ? 'hour' : 'hours' + ); } if ($interval->i > 0) { + return sprintf( + $format, + $interval->i, + $interval->i === 1 ? 'minute' : 'minutes' + ); return $interval->i === 1 ? '1 minute ago' : $interval->i . ' minutes ago'; } if ($interval->s > 30) { - return $interval->s . ' seconds ago'; + return sprintf( + $format, + $interval->s, + 'seconds' + ); } return 'just now';