Files
eveAI/common/utils/nginx_utils.py
Josako 37819cd7e5 - Correctie reset password en confirm email adress by adapting the prefixed_url_for to use config setting
- Adaptation of DPA and T&Cs
- Refer to privacy statement as DPA, not a privacy statement
- Startup of enforcing signed DPA and T&Cs
- Adaptation of eveai_chat_client to ensure we retrieve correct DPA & T&Cs
2025-10-13 14:28:09 +02:00

108 lines
4.2 KiB
Python

from flask import request, url_for, current_app
from urllib.parse import urlsplit, urlunsplit
import re
VISIBLE_PREFIXES = ('/admin', '/api', '/chat-client')
def _normalize_prefix(raw_prefix: str) -> str:
"""Normalize config prefix to internal form '/admin' or '' if not set."""
if not raw_prefix:
return ''
s = str(raw_prefix).strip()
if not s:
return ''
# remove leading/trailing slashes, then add single leading slash
s = s.strip('/')
if not s:
return ''
return f"/{s}"
def _get_config_prefix() -> str:
"""Return normalized prefix from config EVEAI_APP_PREFIX (config-first)."""
try:
cfg_val = (current_app.config.get('EVEAI_APP_PREFIX') if current_app else None)
return _normalize_prefix(cfg_val)
except Exception:
return ''
def _derive_visible_prefix():
# 1) Edge-provided header (beste en meest expliciete bron)
xfp = request.headers.get('X-Forwarded-Prefix')
current_app.logger.debug(f"X-Forwarded-Prefix: {xfp}")
if xfp and any(str(xfp).startswith(p) for p in VISIBLE_PREFIXES):
return str(xfp).rstrip('/')
# 2) Referer fallback: haal het top-level segment uit de Referer path
ref = request.headers.get('Referer') or ''
try:
ref_path = urlsplit(ref).path or ''
m = re.match(r'^/(admin|api|chat-client)(?:\b|/)', ref_path)
if m:
return f"/{m.group(1)}"
except Exception:
pass
# 3) Geen prefix bekend
return ''
def _visible_prefix_for_runtime() -> str:
"""Decide which prefix to use at runtime.
Priority: config EVEAI_APP_PREFIX; optional dynamic fallback if enabled.
"""
cfg_prefix = _get_config_prefix()
if cfg_prefix:
current_app.logger.debug(f"prefixed_url_for: using config prefix: {cfg_prefix}")
return cfg_prefix
# Optional dynamic fallback
use_fallback = bool(current_app.config.get('EVEAI_USE_DYNAMIC_PREFIX_FALLBACK', False)) if current_app else False
if use_fallback:
dyn = _derive_visible_prefix()
current_app.logger.debug(f"prefixed_url_for: using dynamic fallback prefix: {dyn}")
return dyn
current_app.logger.debug("prefixed_url_for: no prefix configured, no fallback enabled")
return ''
def prefixed_url_for(endpoint, **values):
"""
Gedrag:
- Default (_external=False, for_redirect=False): retourneer relatief pad (zonder leading '/')
voor templates/JS. De dynamische <base> zorgt voor correcte resolutie onder het zichtbare prefix.
- _external=True: bouw absolute URL (schema/host). Pad wordt geprefixt met config prefix (indien gezet),
of optioneel met dynamische fallback wanneer geactiveerd.
- for_redirect=True: geef root-absoluut pad inclusief zichtbaar top-prefix, geschikt
voor HTTP Location headers. Backwards compat: _as_location=True wordt behandeld als for_redirect.
"""
external = values.pop('_external', False)
# Backwards compatibility met oudere paramnaam
if values.pop('_as_location', False):
values['for_redirect'] = True
for_redirect = values.pop('for_redirect', False)
generated_url = url_for(endpoint, **values) # bv. "/user/tenant_overview"
path, query, fragment = urlsplit(generated_url)[2:5]
if external:
scheme = request.headers.get('X-Forwarded-Proto', request.scheme)
host = request.headers.get('Host', request.host)
visible_prefix = _visible_prefix_for_runtime()
new_path = (visible_prefix.rstrip('/') + path) if (visible_prefix and not path.startswith(visible_prefix)) else path
current_app.logger.debug(f"prefixed_url_for external: {scheme}://{host}{new_path}")
return urlunsplit((scheme, host, new_path, query, fragment))
if for_redirect:
visible_prefix = _visible_prefix_for_runtime()
if visible_prefix and not path.startswith(visible_prefix):
composed = f"{visible_prefix}{path}"
current_app.logger.debug(f"prefixed_url_for redirect: {composed}")
return composed
current_app.logger.debug(f"prefixed_url_for redirect (no prefix): {path}")
return path
# Default: relatief pad (zonder leading '/')
rel = path[1:] if path.startswith('/') else path
return rel