summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/Logger.php105
-rwxr-xr-xsrc/ssl_expire_notifier.php73
2 files changed, 178 insertions, 0 deletions
diff --git a/src/lib/Logger.php b/src/lib/Logger.php
new file mode 100644
index 0000000..bf86133
--- /dev/null
+++ b/src/lib/Logger.php
@@ -0,0 +1,105 @@
+<?php
+
+class Logger {
+
+ const DEBUG = 0;
+ const INFO = 1;
+ const WARNING = 2;
+ const ERROR = 3;
+ const FATAL = 4;
+
+ protected static array $levelColors = [
+ self::INFO => 34,
+ self::WARNING => 33,
+ self::ERROR => 31,
+ self::FATAL => 91,
+ ];
+
+ protected static array $levelEmojis = [
+ self::INFO => 'ℹ️',
+ self::WARNING => '⚠️',
+ self::ERROR => '‼️',
+ self::FATAL => '⚡️'
+ ];
+
+ protected string $domain;
+
+ public function __construct(string $domain) {
+ $this->domain = $domain;
+ }
+
+ protected function stderr(string $message, $color = null) {
+ $fmt = "[%s] %s";
+ if (is_int($color))
+ $fmt = "\033[{$color}m$fmt\033[0m";
+ $fmt .= "\n";
+ $message = strip_tags($message);
+ fprintf(STDERR, $fmt, $this->domain, $message);
+ }
+
+ protected function telegram(string $message) {
+ global $config;
+
+ $url = 'https://api.telegram.org/bot'.$config['telegram_token'].'/sendMessage';
+ $query_content = http_build_query([
+ 'chat_id' => $config['telegram_chat_id'],
+ 'text' => $message,
+ 'parse_mode' => 'html'
+ ]);
+
+ $ctx = stream_context_create([
+ 'http' => [
+ 'header' => [
+ 'Content-type: application/x-www-form-urlencoded',
+ 'Content-Length: '.strlen($query_content)
+ ],
+ 'method' => 'POST',
+ 'content' => $query_content
+ ]
+ ]);
+
+ $fp = @fopen($url, 'r', false, $ctx);
+ if ($fp === false) {
+ $this->stderr("fopen failed");
+ return;
+ }
+
+ $result = stream_get_contents($fp);
+ fclose($fp);
+
+ $result = json_decode($result, true);
+ if (!$result['ok'])
+ $this->stderr("telegram did not OK");
+ }
+
+ protected function report(int $level, string $message) {
+ global $config;
+
+ if ($config['verbose'])
+ $this->stderr($message, self::$levelColors[$level] ?? null);
+
+ if ($level != self::DEBUG && ($config['telegram_enabled'] ?? 1) == 1)
+ $this->telegram(self::$levelEmojis[$level].' '.$this->domain.': '.$message);
+ }
+
+ public function debug(string $message) {
+ $this->report(self::DEBUG, $message);
+ }
+
+ public function info(string $message) {
+ $this->report(self::INFO, $message);
+ }
+
+ public function warn(string $message) {
+ $this->report(self::WARNING, $message);
+ }
+
+ public function error(string $message) {
+ $this->report(self::ERROR, $message);
+ }
+
+ public function fatal(string $message) {
+ $this->report(self::FATAL, $message);
+ }
+
+} \ No newline at end of file
diff --git a/src/ssl_expire_notifier.php b/src/ssl_expire_notifier.php
new file mode 100755
index 0000000..e6549e6
--- /dev/null
+++ b/src/ssl_expire_notifier.php
@@ -0,0 +1,73 @@
+#!/usr/bin/env php
+<?php
+
+require_once __DIR__.'/lib/Logger.php';
+
+error_reporting(E_ALL);
+ini_set('display_errors', 1);
+
+$file = getenv('HOME').'/.config/ssl_expire_notifier.ini';
+if (!file_exists($file))
+ die('ERROR: config '.$file.' not found');
+
+$config = parse_ini_file($file);
+
+function ssl_expire_notifier() {
+ global $config;
+ $now = time();
+
+ foreach ($config['hosts'] as $host) {
+ $logger = new Logger($host);
+ if (($pos = strpos($host, ':')) !== false) {
+ $port = substr($host, $pos+1);
+ if (!is_numeric($port)) {
+ $logger->error("failed to parse host");
+ continue;
+ }
+ $host = substr($host, 0, $pos);
+ } else {
+ $port = 443;
+ }
+
+ $ipv4 = gethostbyname($host);
+ if (!$ipv4 || $ipv4 == $host) {
+ $logger->error("failed to resolve");
+ continue;
+ }
+
+ $logger->debug("resolved to $ipv4");
+
+ $get = stream_context_create([
+ 'ssl' => [
+ 'capture_peer_cert' => true,
+ 'verify_peer' => false,
+ 'verify_peer_name' => false,
+ 'allow_self_signed' => true,
+ 'verify_depth' => 0,
+ ]
+ ]);
+ $read = stream_socket_client('ssl://'.$host.':'.$port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $get);
+ $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));
+
+ 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');
+ }
+ }
+}
+
+ssl_expire_notifier(); \ No newline at end of file