loopback_ban_exempt: force-add egen custom_component (custom_components er ellers gitignored)
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
"""Exempt loopback addresses (127.0.0.1 / ::1) from Home Assistant's HTTP login-ban handling.
|
||||
|
||||
Home Assistant has no built-in way to whitelist an IP from the ``http`` ban
|
||||
system. Local tools running on the same host (e.g. a VS Code session that
|
||||
queries ``/api/config`` without a token) therefore show up as failed login
|
||||
attempts from ``127.0.0.1`` and can eventually get localhost banned, which
|
||||
would break legitimate local access.
|
||||
|
||||
This integration wraps ``process_wrong_login`` so that any request whose remote
|
||||
address is a loopback address is silently ignored. External addresses are still
|
||||
processed normally, so ``login_attempts_threshold`` protection stays intact.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from ipaddress import ip_address
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = "loopback_ban_exempt"
|
||||
|
||||
# Modules that hold a reference to process_wrong_login (either the definition
|
||||
# itself or an ``from ... import process_wrong_login``). All must be patched.
|
||||
_TARGET_MODULES = (
|
||||
"homeassistant.components.http.ban",
|
||||
"homeassistant.components.auth.login_flow",
|
||||
"homeassistant.components.websocket_api.auth",
|
||||
)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Patch the ban handler to skip loopback addresses."""
|
||||
from homeassistant.components.http import ban as ban_module
|
||||
|
||||
original = ban_module.process_wrong_login
|
||||
|
||||
async def process_wrong_login(request):
|
||||
"""Ignore loopback, otherwise defer to the original handler."""
|
||||
remote = getattr(request, "remote", None)
|
||||
try:
|
||||
if remote is not None and ip_address(remote).is_loopback:
|
||||
return None
|
||||
except ValueError:
|
||||
pass
|
||||
return await original(request)
|
||||
|
||||
patched = 0
|
||||
for mod_path in _TARGET_MODULES:
|
||||
try:
|
||||
module = __import__(mod_path, fromlist=["process_wrong_login"])
|
||||
except ImportError:
|
||||
continue
|
||||
if getattr(module, "process_wrong_login", None) is not None:
|
||||
module.process_wrong_login = process_wrong_login
|
||||
patched += 1
|
||||
|
||||
_LOGGER.info(
|
||||
"Loopback ban exemption active (patched %s reference(s))", patched
|
||||
)
|
||||
return True
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"domain": "loopback_ban_exempt",
|
||||
"name": "Loopback Ban Exempt",
|
||||
"version": "1.0.0",
|
||||
"documentation": "https://www.home-assistant.io/integrations/http/",
|
||||
"dependencies": ["http"],
|
||||
"codeowners": [],
|
||||
"iot_class": "local_push"
|
||||
}
|
||||
Reference in New Issue
Block a user