Initial Source code version

This commit is contained in:
Frank Agerholm 2025-12-11 12:07:17 +01:00
commit d979374cbc
23 changed files with 2628 additions and 0 deletions

View file

@ -0,0 +1,70 @@
from typing import Dict, Any, List
from sqlalchemy import select
from app.db import SessionLocal
from app.models import Task
from app.workers.base_worker import BaseWorker
from app.job_registry import routing_key
from app.workers.utils import resolve_mx, smtp_starttls_probe, parse_cert_time
from datetime import datetime, timezone
class CertValidityWorker(BaseWorker):
async def process(self, payload: dict, **meta) -> dict:
domain = payload.get("domain")
job_id = meta.get('job_id')
if not domain:
raise ValueError("payload.domain is required")
# Hol MX aus MXValidation
mx_hosts: List[str] = []
if job_id:
async with SessionLocal() as session:
res = await session.execute(select(Task).where(Task.job_id == job_id, Task.name == 'MXValidation'))
mx_task = res.scalar_one_or_none()
if mx_task and mx_task.result and 'mx_records' in mx_task.result:
mx_hosts = [r['exchange'] for r in mx_task.result.get('mx_records', [])]
if not mx_hosts:
mx = await resolve_mx(domain)
mx_hosts = [m.exchange for m in mx]
results: List[Dict[str, Any]] = []
now = datetime.now(timezone.utc)
for host in mx_hosts:
probe = await smtp_starttls_probe(host, 25)
cert = probe.get('cert')
entry: Dict[str, Any] = {'host': host, 'tls_established': probe.get('tls_established', False)}
if cert:
nb = parse_cert_time(cert.get('notBefore')) if cert.get('notBefore') else None
na = parse_cert_time(cert.get('notAfter')) if cert.get('notAfter') else None
is_valid = None
days_remaining = None
if nb and na:
# Hinweis: parse_cert_time gibt naive UTC basierend auf 'GMT'; wir machen sie timezone-aware UTC
nb = nb.replace(tzinfo=timezone.utc)
na = na.replace(tzinfo=timezone.utc)
is_valid = (nb <= now <= na)
days_remaining = int((na - now).total_seconds() // 86400)
entry.update({
'not_before': nb.isoformat() if nb else None,
'not_after': na.isoformat() if na else None,
'valid_now': is_valid,
'days_remaining': days_remaining,
'subject': cert.get('subject'),
'issuer': cert.get('issuer'),
})
else:
entry['error'] = probe.get('error') or ('no cert (starttls_advertised=' + str(probe.get('starttls_advertised')) + ')')
results.append(entry)
return {
'certs': results,
'summary': {
'total_hosts': len(results),
'valid_now': sum(1 for r in results if r.get('valid_now')),
'expiring_soon_14d': sum(1 for r in results if isinstance(r.get('days_remaining'), int) and r['days_remaining'] <= 14),
}
}
async def main():
worker = CertValidityWorker(routing_key("MailCheck", "CertValidity"), worker_id="cert-worker-1")
await worker.run()
if __name__ == "__main__":
import asyncio as _a
_a.run(main())