ssl-check.py
Проверяет срок действия SSL-сертификатов для списка доменов. Если до истечения менее 14 дней — отправляет уведомление в Telegram. Без внешних зависимостей, работает на стандартной библиотеке Python.
Зависимости
- Python 3.9+
- Для Telegram-уведомлений: бот-токен и chat ID
Использование
# Проверка одного домена python3 ssl-check.py example.com # Проверка списка из файла python3 ssl-check.py -f domains.txt # С уведомлением в Telegram python3 ssl-check.py -f domains.txt --tg-token BOT_TOKEN --tg-chat CHAT_ID
Код
#!/usr/bin/env python3
"""ssl-check.py — проверка сроков SSL-сертификатов."""
import ssl
import socket
import argparse
import sys
from datetime import datetime, timezone
from urllib.request import urlopen, Request
from urllib.parse import urlencode
def get_cert_expiry(hostname: str, port: int = 443, timeout: int = 10) -> datetime:
"""Получает дату истечения SSL-сертификата."""
ctx = ssl.create_default_context()
with socket.create_connection((hostname, port), timeout=timeout) as sock:
with ctx.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
expiry_str = cert["notAfter"]
return datetime.strptime(expiry_str, "%b %d %H:%M:%S %Y %Z").replace(
tzinfo=timezone.utc
)
def send_telegram(token: str, chat_id: str, message: str) -> None:
"""Отправляет сообщение в Telegram."""
url = f"https://api.telegram.org/bot{token}/sendMessage"
data = urlencode({"chat_id": chat_id, "text": message, "parse_mode": "HTML"}).encode()
req = Request(url, data=data, method="POST")
urlopen(req, timeout=10)
def main():
parser = argparse.ArgumentParser(description="Проверка SSL-сертификатов")
parser.add_argument("domains", nargs="*", help="Домены для проверки")
parser.add_argument("-f", "--file", help="Файл со списком доменов")
parser.add_argument("--days", type=int, default=14, help="Порог в днях (по умолчанию 14)")
parser.add_argument("--tg-token", help="Telegram bot token")
parser.add_argument("--tg-chat", help="Telegram chat ID")
args = parser.parse_args()
domains = list(args.domains)
if args.file:
with open(args.file) as f:
domains.extend(line.strip() for line in f if line.strip())
if not domains:
parser.error("Укажите хотя бы один домен")
now = datetime.now(timezone.utc)
alerts = []
for domain in domains:
try:
expiry = get_cert_expiry(domain)
days_left = (expiry - now).days
status = "OK" if days_left > args.days else "ВНИМАНИЕ"
symbol = "✓" if days_left > args.days else "⚠"
print(f" {symbol} {domain}: {days_left} дн. (до {expiry:%d.%m.%Y})")
if days_left <= args.days:
alerts.append(f"⚠ {domain}: осталось {days_left} дн.")
except Exception as e:
print(f" ✗ {domain}: ошибка — {e}")
alerts.append(f"✗ {domain}: {e}")
if alerts and args.tg_token and args.tg_chat:
msg = "<b>SSL Check</b>\n" + "\n".join(alerts)
send_telegram(args.tg_token, args.tg_chat, msg)
print(f"\nУведомление отправлено в Telegram.")
if __name__ == "__main__":
main()