diff options
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | composer.json | 3 | ||||
-rw-r--r-- | composer.lock | 209 | ||||
-rwxr-xr-x | src/ssl_expire_notifier.php | 89 |
4 files changed, 293 insertions, 23 deletions
@@ -1,6 +1,11 @@ # ssl_expire_notifier -Simple PHP script that checks SSL certificates expiration dates for a list of given domains +Simple PHP script that checks + +- SSL certificates expiration dates +- domain registration expiration dates + +for a list of given domains and notifies you via Telegram if some of them are about to expire. Supposed to be run by cron daily or so. @@ -15,8 +20,12 @@ telegram_token = "your_bot_token" telegram_chat_id = "your_chat_id" verbose = 1 -warn_days = 60 -error_days = 30 + +ssl_warn_days = 14 +ssl_error_days = 5 + +reg_warn_days = 30 +reg_error_days = 15 hosts[] = example.org hosts[] = mail.example.com:993 diff --git a/composer.json b/composer.json index 43804f4..f936c19 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,8 @@ { "require": { "ext-openssl": "*", - "ext-json": "*" + "ext-json": "*", + "io-developer/php-whois": "^4.1" }, "config": { "platform": { diff --git a/composer.lock b/composer.lock index 09efa8a..be1e535 100644 --- a/composer.lock +++ b/composer.lock @@ -4,15 +4,218 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8d070178755c320c69f93ee4800660ef", - "packages": [], + "content-hash": "abc998f727883b7b212185e84742fa24", + "packages": [ + { + "name": "io-developer/php-whois", + "version": "4.1.7", + "source": { + "type": "git", + "url": "https://github.com/io-developer/php-whois.git", + "reference": "6c6cd1d7392d76ba18752cf37227433b50b0bac9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/io-developer/php-whois/zipball/6c6cd1d7392d76ba18752cf37227433b50b0bac9", + "reference": "6c6cd1d7392d76ba18752cf37227433b50b0bac9", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=7.2", + "true/punycode": "^2.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Iodev\\": "src/Iodev/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sergey Sedyshev", + "email": "i.o.developer@gmail.com", + "homepage": "https://github.com/io-developer" + } + ], + "description": "PHP WHOIS provides parsed and raw whois lookup of domains and ASN routes. PHP 5.4+ and 7+ compatible ", + "homepage": "https://github.com/io-developer/php-whois", + "keywords": [ + "asn", + "domain", + "info", + "lookup", + "parser", + "php", + "query", + "routes", + "tld", + "whois", + "црщшы" + ], + "support": { + "issues": "https://github.com/io-developer/php-whois/issues", + "source": "https://github.com/io-developer/php-whois/tree/4.1.7" + }, + "time": "2022-06-14T10:29:24+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "true/punycode", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/true/php-punycode.git", + "reference": "a4d0c11a36dd7f4e7cd7096076cab6d3378a071e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/true/php-punycode/zipball/a4d0c11a36dd7f4e7cd7096076cab6d3378a071e", + "reference": "a4d0c11a36dd7f4e7cd7096076cab6d3378a071e", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.7", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "TrueBV\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Renan Gonçalves", + "email": "renan.saddam@gmail.com" + } + ], + "description": "A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)", + "homepage": "https://github.com/true/php-punycode", + "keywords": [ + "idna", + "punycode" + ], + "support": { + "issues": "https://github.com/true/php-punycode/issues", + "source": "https://github.com/true/php-punycode/tree/master" + }, + "abandoned": true, + "time": "2016-11-16T10:37:54+00:00" + } + ], "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, - "platform": [], + "platform": { + "ext-openssl": "*", + "ext-json": "*" + }, "platform-dev": [], + "platform-overrides": { + "php": "7.4" + }, "plugin-api-version": "2.3.0" } diff --git a/src/ssl_expire_notifier.php b/src/ssl_expire_notifier.php index e6549e6..5f01bcc 100755 --- a/src/ssl_expire_notifier.php +++ b/src/ssl_expire_notifier.php @@ -1,17 +1,74 @@ #!/usr/bin/env php <?php +require_once __DIR__.'/../vendor/autoload.php'; require_once __DIR__.'/lib/Logger.php'; +use Iodev\Whois\Factory; + error_reporting(E_ALL); ini_set('display_errors', 1); +const TIME_FMT = 'd.m.Y, H:i:s'; +const TYPE_SSL = 0; +const TYPE_WHOIS = 1; + $file = getenv('HOME').'/.config/ssl_expire_notifier.ini'; if (!file_exists($file)) die('ERROR: config '.$file.' not found'); +$now = time(); $config = parse_ini_file($file); +function handle_result(int $type, string $host, int $exp, Logger $logger) { + global $now, $config; + + static $cfg_prefixes = [ + TYPE_SSL => 'ssl_', + TYPE_WHOIS => 'reg_' + ]; + static $subtitles = [ + TYPE_SSL => 'SSL', + TYPE_WHOIS => 'REGISTRATION' + ]; + + $cfg_prefix = $cfg_prefixes[$type]; + $subtitle = $subtitles[$type]; + + $logger->debug("{$subtitle}: valid till ".date(TIME_FMT, $exp)); + + if ($exp <= $now) { + $logger->fatal($subtitle.': already expired at '.date(TIME_FMT, $exp)); + } else { + $method = null; + if ($exp-$now < 86400*$config[$cfg_prefix.'error_days']) + $method = 'error'; + else if ($exp-$now < 86400*$config[$cfg_prefix.'warn_days']) + $method = 'warn'; + + if ($method !== null) + call_user_func([$logger, $method], "{$subtitle}: expires at ".date(TIME_FMT, $exp)); + else + $logger->debug('ok'); + } +} + +function get_top_domains() { + global $config; + $domains = array_map(function(string $d) { + if (($pos = strpos($d, ':')) !== false) + $d = substr($d, 0, $pos); + $words = explode('.', $d); + if (count($words) < 2) { + trigger_error('weird domain: '.$d); + return $d; + } + $words = array_reverse($words); + return "{$words[1]}.{$words[0]}"; + }, $config['hosts']); + return array_values(array_unique($domains)); +} + function ssl_expire_notifier() { global $config; $now = time(); @@ -50,24 +107,24 @@ function ssl_expire_notifier() { $cert = stream_context_get_params($read); $cert_info = openssl_x509_parse($cert['options']['ssl']['peer_certificate']); - $valid_till = $cert_info['validTo_time_t']; - $logger->debug("valid till ".date('d.m.Y, H:i:s', $valid_till)); + handle_result(TYPE_SSL, $host, $cert_info['validTo_time_t'], $logger); + } +} - if ($valid_till <= $now) { - $logger->fatal('already expired at '.date('d.m.Y, H:i:s', $valid_till)); - } else { - $method = null; - if ($valid_till-$now < 86400*$config['error_days']) - $method = 'error'; - else if ($valid_till-$now < 86400*$config['warn_days']) - $method = 'warn'; - - if ($method !== null) - call_user_func([$logger, $method], "expires at ".date('d.m.Y, H:i:s', $valid_till)); - else - $logger->debug('ok'); +function whois_expire_notifier() { + $whois = Factory::get()->createWhois(); + + $domains = get_top_domains(); + foreach ($domains as $domain) { + $logger = new Logger($domain); + try { + $info = $whois->loadDomainInfo($domain); + handle_result(TYPE_WHOIS, $domain, $info->expirationDate, $logger); + } catch (\Iodev\Whois\Exceptions\WhoisException $e) { + $logger->error("WhoisException: ".$e->getMessage()); } } } -ssl_expire_notifier();
\ No newline at end of file +ssl_expire_notifier(); +whois_expire_notifier();
\ No newline at end of file |