Return status constants instead of strings
This commit is contained in:
@@ -10,6 +10,15 @@ import datetime
|
|||||||
__version__ = "1.0.0"
|
__version__ = "1.0.0"
|
||||||
__author__ = "Thomas Oettli <spacefreak@noop.ch>"
|
__author__ = "Thomas Oettli <spacefreak@noop.ch>"
|
||||||
|
|
||||||
|
# DynDNS-compatible response statuses
|
||||||
|
STATUS_GOOD = "good"
|
||||||
|
STATUS_NOCHG = "nochg"
|
||||||
|
STATUS_BADAUTH = "badauth"
|
||||||
|
STATUS_NOHOST = "nohost"
|
||||||
|
STATUS_DNSERR = "dnserr"
|
||||||
|
STATUS_ABUSE = "abuse"
|
||||||
|
STATUS_BADIP = "badip"
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"app",
|
"app",
|
||||||
"cleanup",
|
"cleanup",
|
||||||
@@ -23,6 +32,13 @@ __all__ = [
|
|||||||
"models",
|
"models",
|
||||||
"ratelimit",
|
"ratelimit",
|
||||||
"server",
|
"server",
|
||||||
|
"STATUS_GOOD",
|
||||||
|
"STATUS_NOCHG",
|
||||||
|
"STATUS_BADAUTH",
|
||||||
|
"STATUS_NOHOST",
|
||||||
|
"STATUS_DNSERR",
|
||||||
|
"STATUS_ABUSE",
|
||||||
|
"STATUS_BADIP",
|
||||||
]
|
]
|
||||||
|
|
||||||
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S %Z"
|
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S %Z"
|
||||||
|
|||||||
@@ -14,7 +14,17 @@ from urllib.parse import parse_qs, urlparse
|
|||||||
|
|
||||||
import argon2
|
import argon2
|
||||||
|
|
||||||
from . import datetime_str, utc_now
|
from . import (
|
||||||
|
datetime_str,
|
||||||
|
utc_now,
|
||||||
|
STATUS_GOOD,
|
||||||
|
STATUS_NOCHG,
|
||||||
|
STATUS_BADAUTH,
|
||||||
|
STATUS_NOHOST,
|
||||||
|
STATUS_DNSERR,
|
||||||
|
STATUS_ABUSE,
|
||||||
|
STATUS_BADIP,
|
||||||
|
)
|
||||||
from .cleanup import ExpiredRecordsCleanupThread, RateLimitCleanupThread
|
from .cleanup import ExpiredRecordsCleanupThread, RateLimitCleanupThread
|
||||||
from .logging import clear_txn_id, set_txn_id
|
from .logging import clear_txn_id, set_txn_id
|
||||||
from .models import DoesNotExist, get_hostname_for_user, get_user
|
from .models import DoesNotExist, get_hostname_for_user, get_user
|
||||||
@@ -196,7 +206,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
logging.warning(
|
logging.warning(
|
||||||
f"Rate limited (bad): client={client_ip}, "
|
f"Rate limited (bad): client={client_ip}, "
|
||||||
f"retry_at={datetime_str(retry_at)}")
|
f"retry_at={datetime_str(retry_at)}")
|
||||||
self.respond(429, "abuse")
|
self.respond(429, STATUS_ABUSE)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Parse URL
|
# Parse URL
|
||||||
@@ -219,7 +229,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
if not username or not password:
|
if not username or not password:
|
||||||
logging.warning(f"Auth failed: client={client_ip} user=anonymous")
|
logging.warning(f"Auth failed: client={client_ip} user=anonymous")
|
||||||
self._handle_bad_request(client_ip, 401, "badauth")
|
self._handle_bad_request(client_ip, 401, STATUS_BADAUTH)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Validate credentials
|
# Validate credentials
|
||||||
@@ -228,14 +238,14 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
self.app.password_hasher.verify(user.password_hash, password)
|
self.app.password_hasher.verify(user.password_hash, password)
|
||||||
except (DoesNotExist, argon2.exceptions.VerifyMismatchError):
|
except (DoesNotExist, argon2.exceptions.VerifyMismatchError):
|
||||||
logging.warning(f"Auth failed: client={client_ip} user={username}")
|
logging.warning(f"Auth failed: client={client_ip} user={username}")
|
||||||
self._handle_bad_request(client_ip, 401, "badauth")
|
self._handle_bad_request(client_ip, 401, STATUS_BADAUTH)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get hostname parameter
|
# Get hostname parameter
|
||||||
hostname_param = extract_param(params, endpoint["params"]["hostname"])
|
hostname_param = extract_param(params, endpoint["params"]["hostname"])
|
||||||
if not hostname_param:
|
if not hostname_param:
|
||||||
logging.warning(f"Missing hostname: client={client_ip} user={username}")
|
logging.warning(f"Missing hostname: client={client_ip} user={username}")
|
||||||
self._handle_bad_request(client_ip, 400, "nohost")
|
self._handle_bad_request(client_ip, 400, STATUS_NOHOST)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Validate and encode hostname
|
# Validate and encode hostname
|
||||||
@@ -245,7 +255,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
logging.warning(
|
logging.warning(
|
||||||
f"Invalid hostname: client={client_ip}, "
|
f"Invalid hostname: client={client_ip}, "
|
||||||
f"hostname={hostname_param}")
|
f"hostname={hostname_param}")
|
||||||
self._handle_bad_request(client_ip, 400, "nohost")
|
self._handle_bad_request(client_ip, 400, STATUS_NOHOST)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check hostname ownership
|
# Check hostname ownership
|
||||||
@@ -256,7 +266,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
f"Access denied: client={client_ip} user={username} "
|
f"Access denied: client={client_ip} user={username} "
|
||||||
f"hostname={hostname_param}"
|
f"hostname={hostname_param}"
|
||||||
)
|
)
|
||||||
self._handle_bad_request(client_ip, 403, "nohost")
|
self._handle_bad_request(client_ip, 403, STATUS_NOHOST)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Good rate limit check
|
# Good rate limit check
|
||||||
@@ -266,7 +276,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
logging.warning(
|
logging.warning(
|
||||||
f"Rate limited: client={client_ip}, "
|
f"Rate limited: client={client_ip}, "
|
||||||
f"retry_at={datetime_str(retry_at)}")
|
f"retry_at={datetime_str(retry_at)}")
|
||||||
self.respond(429, "abuse")
|
self.respond(429, STATUS_ABUSE)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Record good request
|
# Record good request
|
||||||
@@ -305,7 +315,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
else:
|
else:
|
||||||
ipv6 = myip
|
ipv6 = myip
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return (400, "badip")
|
return (400, STATUS_BADIP)
|
||||||
|
|
||||||
# Process myip6 parameter
|
# Process myip6 parameter
|
||||||
if myip6:
|
if myip6:
|
||||||
@@ -314,9 +324,9 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
if rtype == "AAAA":
|
if rtype == "AAAA":
|
||||||
ipv6 = myip6
|
ipv6 = myip6
|
||||||
else:
|
else:
|
||||||
return (400, "badip")
|
return (400, STATUS_BADIP)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return (400, "badip")
|
return (400, STATUS_BADIP)
|
||||||
|
|
||||||
# Auto-detect from client IP if no params
|
# Auto-detect from client IP if no params
|
||||||
if ipv4 is None and ipv6 is None:
|
if ipv4 is None and ipv6 is None:
|
||||||
@@ -327,7 +337,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
else:
|
else:
|
||||||
ipv6 = ip
|
ipv6 = ip
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return (400, "badip")
|
return (400, STATUS_BADIP)
|
||||||
|
|
||||||
now = utc_now()
|
now = utc_now()
|
||||||
|
|
||||||
@@ -352,7 +362,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
f"DNS update failed: client={client_ip} hostname={hostname.hostname} "
|
f"DNS update failed: client={client_ip} hostname={hostname.hostname} "
|
||||||
f"zone={hostname.zone} ipv4={ipv4} error={e}"
|
f"zone={hostname.zone} ipv4={ipv4} error={e}"
|
||||||
)
|
)
|
||||||
return (500, "dnserr")
|
return (500, STATUS_DNSERR)
|
||||||
|
|
||||||
if ipv6:
|
if ipv6:
|
||||||
hostname.last_ipv6_update = now
|
hostname.last_ipv6_update = now
|
||||||
@@ -373,7 +383,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
f"DNS update failed: client={client_ip} hostname={hostname.hostname} "
|
f"DNS update failed: client={client_ip} hostname={hostname.hostname} "
|
||||||
f"zone={hostname.zone} ipv6={ipv6} error={e}"
|
f"zone={hostname.zone} ipv6={ipv6} error={e}"
|
||||||
)
|
)
|
||||||
return (500, "dnserr")
|
return (500, STATUS_DNSERR)
|
||||||
|
|
||||||
# Update database
|
# Update database
|
||||||
hostname.save()
|
hostname.save()
|
||||||
@@ -394,7 +404,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
f"zone={hostname.zone}{changed_addrs} notify_change={str(notify_change).lower()}"
|
f"zone={hostname.zone}{changed_addrs} notify_change={str(notify_change).lower()}"
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
200, "nochg",
|
200, STATUS_NOCHG,
|
||||||
{"ipv4": hostname.last_ipv4, "ipv6": hostname.last_ipv6}
|
{"ipv4": hostname.last_ipv4, "ipv6": hostname.last_ipv6}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -415,7 +425,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
|||||||
logging.error(f"Sending change notification error: {e}")
|
logging.error(f"Sending change notification error: {e}")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
200, "good",
|
200, STATUS_GOOD,
|
||||||
{"ipv4": hostname.last_ipv4, "ipv6": hostname.last_ipv6}
|
{"ipv4": hostname.last_ipv4, "ipv6": hostname.last_ipv6}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user