61 lines
2.4 KiB
Python
61 lines
2.4 KiB
Python
from flask import request, url_for
|
|
from urllib.parse import urlsplit, urlunsplit
|
|
import re
|
|
|
|
VISIBLE_PREFIXES = ('/admin', '/api', '/chat-client')
|
|
|
|
def _derive_visible_prefix():
|
|
# 1) Edge-provided header (beste en meest expliciete bron)
|
|
xfp = request.headers.get('X-Forwarded-Prefix')
|
|
if xfp and any(xfp.startswith(p) for p in VISIBLE_PREFIXES):
|
|
return 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 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). Als X-Forwarded-Prefix aanwezig is,
|
|
prefixeer de path daarmee (handig voor e-mails/deeplinks).
|
|
- 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)
|
|
xfp = request.headers.get('X-Forwarded-Prefix', '') or ''
|
|
new_path = (xfp.rstrip('/') + path) if (xfp and not path.startswith(xfp)) else path
|
|
return urlunsplit((scheme, host, new_path, query, fragment))
|
|
|
|
if for_redirect:
|
|
visible_prefix = _derive_visible_prefix()
|
|
if visible_prefix and not path.startswith(visible_prefix):
|
|
return f"{visible_prefix}{path}"
|
|
# root-absoluut pad, zonder prefix als onbekend
|
|
return path
|
|
|
|
# Default: relatief pad
|
|
return path[1:] if path.startswith('/') else path |