diff --git a/babybuddy/middleware.py b/babybuddy/middleware.py index 0d42cb8c..7e988e70 100644 --- a/babybuddy/middleware.py +++ b/babybuddy/middleware.py @@ -2,11 +2,12 @@ from os import getenv from time import time import pytz +from urllib.parse import urlunsplit, urlsplit from django.conf import settings from django.utils import timezone, translation from django.contrib.auth.middleware import RemoteUserMiddleware - +from django.http import HttpRequest class UserLanguageMiddleware: """ @@ -88,3 +89,37 @@ class CustomRemoteUser(RemoteUserMiddleware): """ header = getenv("PROXY_HEADER", "HTTP_REMOTE_USER") + + +class HomeAssistant: + def __init__(self, get_response): + self.get_response = get_response + self.use_x_ingress_path_rewrite = settings.HOME_ASSISTANT_USE_X_INGRESS_PATH + + def __call__(self, request: HttpRequest): + def wrap_x_ingress_path(org_func): + if request.headers.get("HTTP_X_HASS_SOURCE") != "core.ingress": + return org_func + x_ingress_path = request.headers.get("HTTP_X_INGRESS_PATH") + if x_ingress_path is None: + return org_func + + def wrapper(*args, **kwargs): + url = org_func(*args, **kwargs) + + url_parts = urlsplit(url) + url = urlunsplit( + url_parts._replace(path=x_ingress_path + url_parts.path) + ) + + return url + return wrapper + + if self.use_x_ingress_path_rewrite: + request.build_absolute_uri = wrap_x_ingress_path( + request.build_absolute_uri + ) + + return self.get_response(request) + + \ No newline at end of file diff --git a/babybuddy/settings/base.py b/babybuddy/settings/base.py index 153748ca..8c9aceea 100644 --- a/babybuddy/settings/base.py +++ b/babybuddy/settings/base.py @@ -64,6 +64,7 @@ MIDDLEWARE = [ "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "axes.middleware.AxesMiddleware", + "babybuddy.middleware.HomeAssistant", ] @@ -351,9 +352,13 @@ ROLLING_SESSION_REFRESH = 86400 DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # Baby Buddy configuration -# See README.md#configuration for details about these settings. +# See https://docs.baby-buddy.net/ for details about these settings. BABY_BUDDY = { "ALLOW_UPLOADS": bool(strtobool(os.environ.get("ALLOW_UPLOADS") or "True")), "READ_ONLY_GROUP_NAME": "read_only", } + +# Home assistant specific configuration + +HOME_ASSISTANT_USE_X_INGRESS_PATH = False diff --git a/docs/configuration/homeassistant.md b/docs/configuration/homeassistant.md new file mode 100644 index 00000000..7a9062ff --- /dev/null +++ b/docs/configuration/homeassistant.md @@ -0,0 +1,17 @@ +# Home Assistant + +## `HOME_ASSISTANT_USE_X_INGRESS_PATH` + +*Default:* `False` + +This setting should be set to `True` if babybuddy is hosted through the [ingress +service of home assistant](https://developers.home-assistant.io/docs/add-ons/presentation/#ingress). + +This setting is necessary so that babybuddy can build correct absolute paths to +itself when run in home assistant. The ingress routing of home assistant +otherwise will obfuscate the true host-url and some functions, like the QR-code +generator for coupling devices might not work correctly. + +**Do not enable this feature on other setups.** Attackers might be able to +use this feature to redirect traffic in unexpected ways by manually adding +`X-Ingress-Path` to the request URL. diff --git a/mkdocs.yml b/mkdocs.yml index 167d0e38..e6fd4a12 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -19,6 +19,7 @@ nav: - 'configuration/email.md' - 'configuration/security.md' - 'configuration/storage.md' + - 'configuration/homeassistant.md' - 'User Guide': - 'user-guide/getting-started.md' - 'user-guide/managing-users.md'