Initial Source code version
This commit is contained in:
parent
90f5f38812
commit
d979374cbc
23 changed files with 2628 additions and 0 deletions
70
app/workers/mail_cert_worker.py
Normal file
70
app/workers/mail_cert_worker.py
Normal 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())
|
||||
Loading…
Add table
Add a link
Reference in a new issue