Skip to content

Redirects

django_spire.core.redirect.generic_redirect

reverse_generic_relation

Source code in django_spire/core/redirect/generic_redirect.py
def reverse_generic_relation(content_object: Any, **kwargs) -> HttpResponse | None:
    from operator import attrgetter

    model_name = content_object.__class__.__name__.lower()

    CONTENT_OBJECT_URL_MAP = {
        # 'APP_NAME': ('URL', ('pk', 'pk')),
    }

    url_path = None

    if isinstance(CONTENT_OBJECT_URL_MAP[model_name], tuple):
        url_path = CONTENT_OBJECT_URL_MAP[model_name][0]

        for kwarg in CONTENT_OBJECT_URL_MAP[model_name][1:]:
            if kwarg[0] == 'pk':
                if isinstance(kwarg[1], str):
                    kwargs[kwarg[0]] = getattr(content_object, kwarg[1])
                elif isinstance(kwarg[1], int):
                    kwargs[kwarg[0]] = kwarg[1]
            elif kwarg[1] == 'parent_pk':
                retriever = attrgetter(kwarg[2])
                kwargs[kwarg[0]] = retriever(content_object)
    elif isinstance(CONTENT_OBJECT_URL_MAP[model_name], str):
        url_path = CONTENT_OBJECT_URL_MAP[model_name]

    if url_path is not None:
        return reverse(url_path, kwargs=kwargs)

    return HttpResponse('home:home')

django_spire.core.redirect.safe_redirect

resolve_url

Resolves a URL name into its corresponding URL path using Django's reverse function.

Parameters:

  • url (str) –

    The URL name or URL string to resolve.

Returns:

  • str

    The reversed URL if successful; otherwise, the original URL.

Source code in django_spire/core/redirect/safe_redirect.py
def resolve_url(url: str) -> str:
    """
    Resolves a URL name into its corresponding URL path using Django's reverse function.

    :param url: The URL name or URL string to resolve.
    :return: The reversed URL if successful; otherwise, the original URL.
    """

    try:
        return reverse(url)
    except NoReverseMatch:
        return url

is_url_valid_and_safe

Determines whether a URL is valid and safe by verifying that it has an allowed host and contains no harmful characters.

Parameters:

  • url (str) –

    The URL to validate.

  • allowed_hosts (set[str]) –

    A set of allowed hostnames.

Returns:

  • bool

    True if the URL is valid and safe; False otherwise.

Source code in django_spire/core/redirect/safe_redirect.py
def is_url_valid_and_safe(url: str, allowed_hosts: set[str]) -> bool:
    """
    Determines whether a URL is valid and safe by verifying that it has an allowed host
    and contains no harmful characters.

    :param url: The URL to validate.
    :param allowed_hosts: A set of allowed hostnames.
    :return: True if the URL is valid and safe; False otherwise.
    """

    if url and url_has_allowed_host_and_scheme(url, allowed_hosts):
        url = urlparse(url)

        harmful = ['<', '>', '"', '{', '}', '|', '\\', '^', '`', '[', ']', ';']

        if any(character in unquote(url.path) for character in harmful):
            return False

        return not any(
            character in unquote(url.query)
            for character in harmful
        )

    return False

safe_redirect_url

Generates a safe redirect URL based on the request's GET parameters and HTTP_REFERER, ensuring that the URL is valid and safe. If neither the return URL nor the referer is valid, a fallback URL is returned.

Parameters:

  • request (WSGIRequest) –

    The WSGIRequest object containing GET and META data.

  • fallback (str, default: '/' ) –

    The fallback URL to use if no valid redirect URL is found; defaults to '/'.

Returns:

  • str

    A safe redirect URL.

Source code in django_spire/core/redirect/safe_redirect.py
def safe_redirect_url(request: WSGIRequest, fallback: str = '/') -> str:
    """
    Generates a safe redirect URL based on the request's GET parameters and
    HTTP_REFERER, ensuring that the URL is valid and safe. If neither the
    return URL nor the referer is valid, a fallback URL is returned.

    :param request: The WSGIRequest object containing GET and META data.
    :param fallback: The fallback URL to use if no valid redirect URL is found; defaults to '/'.
    :return: A safe redirect URL.
    """

    allowed_hosts = {request.get_host()}

    if hasattr(settings, 'ALLOWED_HOSTS'):
        allowed_hosts.update(settings.ALLOWED_HOSTS)

    return_url = request.GET.get('return_url')

    if is_url_valid_and_safe(url=return_url, allowed_hosts=allowed_hosts):
        return resolve_url(return_url)

    referer = request.META.get('HTTP_REFERER')

    if is_url_valid_and_safe(url=referer, allowed_hosts=allowed_hosts):
        url = urlparse(referer)
        query_string = urlencode(parse_qs(url.query), doseq=True)
        path = resolve_url(url.path)

        full = (
            url.scheme,
            url.netloc,
            path,
            '',
            query_string,
            url.fragment
        )

        return urlunparse(full)

    if not is_url_valid_and_safe(url=fallback, allowed_hosts=allowed_hosts):
        fallback = '/'

    return fallback