2022-09-18 21:00:41 +00:00
|
|
|
from os import getenv
|
|
|
|
from time import time
|
2023-07-04 13:00:58 +00:00
|
|
|
from functools import wraps
|
2020-05-17 06:57:00 +00:00
|
|
|
|
2020-02-14 20:35:02 +00:00
|
|
|
import pytz
|
2023-06-04 13:26:17 +00:00
|
|
|
from urllib.parse import urlunsplit, urlsplit
|
2020-02-14 20:35:02 +00:00
|
|
|
|
2020-05-17 06:57:00 +00:00
|
|
|
from django.conf import settings
|
2021-11-28 19:02:23 +00:00
|
|
|
from django.utils import timezone, translation
|
2022-09-18 21:00:41 +00:00
|
|
|
from django.contrib.auth.middleware import RemoteUserMiddleware
|
2023-06-04 13:26:17 +00:00
|
|
|
from django.http import HttpRequest
|
2021-11-12 18:13:08 +00:00
|
|
|
|
2023-07-04 22:18:52 +00:00
|
|
|
|
2021-11-12 18:13:08 +00:00
|
|
|
class UserLanguageMiddleware:
|
|
|
|
"""
|
|
|
|
Customizes settings based on user language setting.
|
|
|
|
"""
|
2022-02-10 00:00:30 +00:00
|
|
|
|
2021-11-12 18:13:08 +00:00
|
|
|
def __init__(self, get_response):
|
|
|
|
self.get_response = get_response
|
|
|
|
|
|
|
|
def __call__(self, request):
|
|
|
|
user = request.user
|
2022-02-10 00:00:30 +00:00
|
|
|
if hasattr(user, "settings") and user.settings.language:
|
2021-11-28 19:18:00 +00:00
|
|
|
language = user.settings.language
|
|
|
|
elif request.LANGUAGE_CODE:
|
|
|
|
language = request.LANGUAGE_CODE
|
|
|
|
else:
|
|
|
|
language = settings.LANGUAGE_CODE
|
|
|
|
|
|
|
|
if language:
|
|
|
|
# Set the language before generating the response.
|
|
|
|
translation.activate(language)
|
|
|
|
|
2021-11-28 19:02:23 +00:00
|
|
|
response = self.get_response(request)
|
|
|
|
|
|
|
|
# Deactivate the translation before the response is sent so it not
|
|
|
|
# reused in other threads.
|
|
|
|
translation.deactivate()
|
|
|
|
|
|
|
|
return response
|
2020-02-14 20:35:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
class UserTimezoneMiddleware:
|
|
|
|
"""
|
2022-06-11 21:27:52 +00:00
|
|
|
Sets the timezone based on a user specific setting. This middleware must run after
|
|
|
|
`django.contrib.auth.middleware.AuthenticationMiddleware` because it uses the
|
|
|
|
request.user object.
|
2020-02-14 20:35:02 +00:00
|
|
|
"""
|
2022-02-10 00:00:30 +00:00
|
|
|
|
2020-02-14 20:35:02 +00:00
|
|
|
def __init__(self, get_response):
|
|
|
|
self.get_response = get_response
|
|
|
|
|
|
|
|
def __call__(self, request):
|
2021-10-17 21:45:53 +00:00
|
|
|
user = request.user
|
2022-02-10 00:00:30 +00:00
|
|
|
if hasattr(user, "settings") and user.settings.timezone:
|
2020-02-14 20:35:02 +00:00
|
|
|
try:
|
2021-10-17 21:45:53 +00:00
|
|
|
timezone.activate(pytz.timezone(user.settings.timezone))
|
2020-02-14 20:35:02 +00:00
|
|
|
except pytz.UnknownTimeZoneError:
|
|
|
|
pass
|
|
|
|
return self.get_response(request)
|
2020-05-17 06:57:00 +00:00
|
|
|
|
2020-05-17 10:11:08 +00:00
|
|
|
|
2020-05-17 06:57:00 +00:00
|
|
|
class RollingSessionMiddleware:
|
|
|
|
"""
|
2021-08-05 13:34:08 +00:00
|
|
|
Periodically resets the session expiry for existing sessions.
|
2020-05-17 06:57:00 +00:00
|
|
|
"""
|
2022-02-10 00:00:30 +00:00
|
|
|
|
2020-05-17 06:57:00 +00:00
|
|
|
def __init__(self, get_response):
|
|
|
|
self.get_response = get_response
|
|
|
|
|
|
|
|
def __call__(self, request):
|
2021-08-05 13:34:08 +00:00
|
|
|
if request.session.keys():
|
2022-02-10 00:00:30 +00:00
|
|
|
session_refresh = request.session.get("session_refresh")
|
2021-08-05 13:34:08 +00:00
|
|
|
if session_refresh:
|
|
|
|
try:
|
2022-09-18 21:00:41 +00:00
|
|
|
delta = int(time()) - session_refresh
|
2021-08-05 13:34:08 +00:00
|
|
|
except (ValueError, TypeError):
|
|
|
|
delta = settings.ROLLING_SESSION_REFRESH + 1
|
|
|
|
if delta > settings.ROLLING_SESSION_REFRESH:
|
2022-09-18 21:00:41 +00:00
|
|
|
request.session["session_refresh"] = int(time())
|
2021-08-05 13:34:08 +00:00
|
|
|
request.session.set_expiry(settings.SESSION_COOKIE_AGE)
|
|
|
|
else:
|
2022-09-18 21:00:41 +00:00
|
|
|
request.session["session_refresh"] = int(time())
|
2020-05-17 06:57:00 +00:00
|
|
|
return self.get_response(request)
|
2022-09-18 21:00:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
class CustomRemoteUser(RemoteUserMiddleware):
|
|
|
|
"""
|
|
|
|
Middleware used for remote authentication when `REVERSE_PROXY_AUTH` is True.
|
|
|
|
"""
|
|
|
|
|
|
|
|
header = getenv("PROXY_HEADER", "HTTP_REMOTE_USER")
|
2023-06-04 13:26:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
class HomeAssistant:
|
2023-07-04 13:00:58 +00:00
|
|
|
"""
|
|
|
|
Django middleware that adds HomeAssistant specific properties and checks
|
|
|
|
to the request-object.
|
|
|
|
|
2023-07-04 22:18:52 +00:00
|
|
|
The middleware is only active if the settings variable
|
2023-07-04 13:00:58 +00:00
|
|
|
`ENABLE_HOME_ASSISTANT_SUPPORT` is set to True. Note that some features
|
2023-07-04 22:18:52 +00:00
|
|
|
remain enabled even if the middleware is set to inactive through the
|
2023-07-04 13:00:58 +00:00
|
|
|
settings.
|
|
|
|
|
|
|
|
Features:
|
2023-07-04 22:18:52 +00:00
|
|
|
|
2023-07-04 13:00:58 +00:00
|
|
|
- request.is_homeassistant_ingress_request (bool)
|
|
|
|
|
|
|
|
Indicates if a request was rerouted through the home assistant ingress
|
2023-07-04 22:18:52 +00:00
|
|
|
service. This parameters is always present regardless of the
|
2023-07-04 13:00:58 +00:00
|
|
|
ENABLE_HOME_ASSISTANT_SUPPORT settings option. It defaults to false
|
|
|
|
if the middleware is disabled.
|
|
|
|
|
|
|
|
- wrapped request.build_absolute_uri function
|
|
|
|
|
|
|
|
The middleware redefines (wraps) the build_absolute_uri function
|
|
|
|
provided by django to allow it to interprete the X-Ingress-Path
|
|
|
|
request header. This allows home assistant to construct correct
|
|
|
|
absolute URLs when run through home assistant's ingress service.
|
|
|
|
"""
|
|
|
|
|
2023-06-04 13:26:17 +00:00
|
|
|
def __init__(self, get_response):
|
|
|
|
self.get_response = get_response
|
2023-07-04 13:00:58 +00:00
|
|
|
self.home_assistant_support_enabled = settings.ENABLE_HOME_ASSISTANT_SUPPORT
|
2023-06-04 13:26:17 +00:00
|
|
|
|
2023-07-04 13:00:58 +00:00
|
|
|
def __wrap_build_absolute_uri(self, request: HttpRequest):
|
2023-06-04 13:26:17 +00:00
|
|
|
def wrap_x_ingress_path(org_func):
|
2023-06-17 22:08:11 +00:00
|
|
|
if not request.is_homeassistant_ingress_request:
|
2023-06-04 13:26:17 +00:00
|
|
|
return org_func
|
2023-06-17 22:08:11 +00:00
|
|
|
x_ingress_path = request.headers.get("X-Ingress-Path")
|
2023-06-04 13:26:17 +00:00
|
|
|
if x_ingress_path is None:
|
|
|
|
return org_func
|
|
|
|
|
2023-07-04 13:00:58 +00:00
|
|
|
@wraps(org_func)
|
2023-06-04 13:26:17 +00:00
|
|
|
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
|
2023-07-04 22:18:52 +00:00
|
|
|
|
2023-06-04 13:26:17 +00:00
|
|
|
return wrapper
|
|
|
|
|
2023-07-04 22:18:52 +00:00
|
|
|
request.build_absolute_uri = wrap_x_ingress_path(request.build_absolute_uri)
|
2023-06-17 22:08:11 +00:00
|
|
|
|
2023-07-04 13:00:58 +00:00
|
|
|
def __call__(self, request: HttpRequest):
|
|
|
|
if self.home_assistant_support_enabled:
|
|
|
|
request.is_homeassistant_ingress_request = (
|
|
|
|
request.headers.get("X-Hass-Source") == "core.ingress"
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
request.is_homeassistant_ingress_request = False
|
|
|
|
|
|
|
|
self.__wrap_build_absolute_uri(request)
|
2023-06-04 13:26:17 +00:00
|
|
|
|
|
|
|
return self.get_response(request)
|