forked from GithubBackups/healthchecks
Email listener: "./manage.py smtpd"
This commit is contained in:
parent
6a57bcfdf3
commit
f2a2241b6b
50
hc/api/management/commands/smtpd.py
Normal file
50
hc/api/management/commands/smtpd.py
Normal file
@ -0,0 +1,50 @@
|
||||
import asyncore
|
||||
import re
|
||||
from smtpd import SMTPServer
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from hc.api.models import Check
|
||||
|
||||
RE_UUID = re.compile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")
|
||||
|
||||
|
||||
class Listener(SMTPServer):
|
||||
def __init__(self, localaddr, stdout):
|
||||
self.stdout = stdout
|
||||
super(Listener, self).__init__(localaddr, None)
|
||||
|
||||
def process_message(self, peer, mailfrom, rcpttos, data):
|
||||
to_parts = rcpttos[0].split("@")
|
||||
code = to_parts[0]
|
||||
|
||||
if not RE_UUID.match(code):
|
||||
self.stdout.write("Not an UUID: %s" % code)
|
||||
return
|
||||
|
||||
try:
|
||||
check = Check.objects.get(code=code)
|
||||
except Check.DoesNotExist:
|
||||
self.stdout.write("Check not found: %s" % code)
|
||||
return
|
||||
|
||||
ua = "Email from %s" % mailfrom
|
||||
check.ping(peer[0], "email", "", ua, data)
|
||||
self.stdout.write("Processed ping for %s" % code)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Listen for ping emails"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument("--host",
|
||||
help="ip address to listen on, default 0.0.0.0",
|
||||
default="0.0.0.0")
|
||||
parser.add_argument('--port',
|
||||
help="port to listen on, default 25",
|
||||
type=int,
|
||||
default=25)
|
||||
|
||||
def handle(self, host, port, *args, **options):
|
||||
listener = Listener((host, port), self.stdout)
|
||||
print("Starting SMTP listener on %s:%d ..." % (host, port))
|
||||
asyncore.loop()
|
@ -188,6 +188,26 @@ class Check(models.Model):
|
||||
def has_confirmation_link(self):
|
||||
return "confirm" in self.last_ping_body.lower()
|
||||
|
||||
def ping(self, remote_addr, scheme, method, ua, body):
|
||||
self.n_pings = models.F("n_pings") + 1
|
||||
self.last_ping = timezone.now()
|
||||
self.last_ping_body = body[:10000]
|
||||
self.alert_after = self.get_alert_after()
|
||||
if self.status in ("new", "paused"):
|
||||
self.status = "up"
|
||||
|
||||
self.save()
|
||||
self.refresh_from_db()
|
||||
|
||||
ping = Ping(owner=self)
|
||||
ping.n = self.n_pings
|
||||
ping.remote_addr = remote_addr
|
||||
ping.scheme = scheme
|
||||
ping.method = method
|
||||
# If User-Agent is longer than 200 characters, truncate it:
|
||||
ping.ua = ua[:200]
|
||||
ping.save()
|
||||
|
||||
|
||||
class Ping(models.Model):
|
||||
n = models.IntegerField(null=True)
|
||||
|
@ -1,7 +1,6 @@
|
||||
from datetime import timedelta as td
|
||||
|
||||
from django.db import connection
|
||||
from django.db.models import F
|
||||
from django.http import (HttpResponse, HttpResponseForbidden,
|
||||
HttpResponseNotFound, JsonResponse)
|
||||
from django.shortcuts import get_object_or_404
|
||||
@ -12,7 +11,7 @@ from django.views.decorators.http import require_POST
|
||||
|
||||
from hc.api import schemas
|
||||
from hc.api.decorators import check_api_key, uuid_or_400, validate_json
|
||||
from hc.api.models import Check, Notification, Ping
|
||||
from hc.api.models import Check, Notification
|
||||
from hc.lib.badges import check_signature, get_badge_svg
|
||||
|
||||
|
||||
@ -22,26 +21,15 @@ from hc.lib.badges import check_signature, get_badge_svg
|
||||
def ping(request, code):
|
||||
check = get_object_or_404(Check, code=code)
|
||||
|
||||
check.n_pings = F("n_pings") + 1
|
||||
check.last_ping = timezone.now()
|
||||
check.last_ping_body = request.body[:10000]
|
||||
check.alert_after = check.get_alert_after()
|
||||
if check.status in ("new", "paused"):
|
||||
check.status = "up"
|
||||
|
||||
check.save()
|
||||
check.refresh_from_db()
|
||||
|
||||
ping = Ping(owner=check)
|
||||
headers = request.META
|
||||
ping.n = check.n_pings
|
||||
remote_addr = headers.get("HTTP_X_FORWARDED_FOR", headers["REMOTE_ADDR"])
|
||||
ping.remote_addr = remote_addr.split(",")[0]
|
||||
ping.scheme = headers.get("HTTP_X_FORWARDED_PROTO", "http")
|
||||
ping.method = headers["REQUEST_METHOD"]
|
||||
# If User-Agent is longer than 200 characters, truncate it:
|
||||
ping.ua = headers.get("HTTP_USER_AGENT", "")[:200]
|
||||
ping.save()
|
||||
remote_addr = remote_addr.split(",")[0]
|
||||
scheme = headers.get("HTTP_X_FORWARDED_PROTO", "http")
|
||||
method = headers["REQUEST_METHOD"]
|
||||
ua = headers.get("HTTP_USER_AGENT", "")
|
||||
body = request.body[:10000]
|
||||
|
||||
check.ping(remote_addr, scheme, method, ua, body)
|
||||
|
||||
response = HttpResponse("OK")
|
||||
response["Access-Control-Allow-Origin"] = "*"
|
||||
|
Loading…
x
Reference in New Issue
Block a user