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