123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- """
- sudo.views
- ~~~~~~~~~~
- :copyright: (c) 2020 by Matt Robenolt.
- :license: BSD, see LICENSE for more details.
- """
- from __future__ import annotations
- from typing import Any
- from urllib.parse import urlparse, urlunparse
- from django.contrib.auth.decorators import login_required
- from django.core.exceptions import ImproperlyConfigured
- from django.http import HttpRequest, HttpResponseRedirect, QueryDict
- from django.http.response import HttpResponseBase
- from django.shortcuts import resolve_url
- from django.template.response import TemplateResponse
- from django.utils.decorators import method_decorator
- from django.utils.http import url_has_allowed_host_and_scheme
- from django.utils.module_loading import import_string
- from django.views.decorators.cache import never_cache
- from django.views.decorators.csrf import csrf_protect
- from django.views.decorators.debug import sensitive_post_parameters
- from django.views.generic import View
- from sudo.forms import SudoForm
- from sudo.settings import REDIRECT_FIELD_NAME, REDIRECT_TO_FIELD_NAME, REDIRECT_URL, URL
- from sudo.utils import grant_sudo_privileges
- class SudoView(View):
- """
- The default view for the sudo mode page. The role of this page is to
- prompt the user for their password again, and if successful, redirect
- them back to ``next``.
- """
- form_class = SudoForm
- template_name = "sudo/sudo.html"
- extra_context: dict[str, str] | None = None
- def handle_sudo(self, request: HttpRequest, context: dict[str, Any]) -> bool:
- return request.method == "POST" and context["form"].is_valid()
- def grant_sudo_privileges(self, request: HttpRequest, redirect_to: str) -> HttpResponseRedirect:
- grant_sudo_privileges(request)
- # Restore the redirect destination from the GET request
- redirect_to = request.session.pop(REDIRECT_TO_FIELD_NAME, redirect_to)
- # Double check we're not redirecting to other sites
- if not url_has_allowed_host_and_scheme(redirect_to, allowed_hosts=(request.get_host(),)):
- redirect_to = resolve_url(REDIRECT_URL)
- return HttpResponseRedirect(redirect_to)
- @method_decorator(sensitive_post_parameters())
- @method_decorator(never_cache)
- @method_decorator(csrf_protect)
- @method_decorator(login_required)
- def dispatch(self, request: HttpRequest, *args: object, **kwargs: object) -> HttpResponseBase:
- redirect_to = request.GET.get(REDIRECT_FIELD_NAME, REDIRECT_URL)
- # Make sure we're not redirecting to other sites
- if not url_has_allowed_host_and_scheme(redirect_to, allowed_hosts=(request.get_host(),)):
- redirect_to = resolve_url(REDIRECT_URL)
- if request.is_sudo():
- return HttpResponseRedirect(redirect_to)
- if request.method == "GET":
- request.session[REDIRECT_TO_FIELD_NAME] = redirect_to
- context = {
- "form": self.form_class(request.user, request.POST or None),
- "request": request,
- REDIRECT_FIELD_NAME: redirect_to,
- }
- if self.handle_sudo(request, context):
- return self.grant_sudo_privileges(request, redirect_to)
- if self.extra_context is not None:
- context.update(self.extra_context)
- return TemplateResponse(request, self.template_name, context)
- def sudo(request: HttpRequest, **kwargs: object) -> HttpResponseBase:
- return SudoView(**kwargs).dispatch(request)
- def redirect_to_sudo(next_url: str, sudo_url: str | None = None) -> HttpResponseRedirect:
- """
- Redirects the user to the login page, passing the given 'next' page
- """
- if sudo_url is None:
- sudo_obj = URL
- else:
- sudo_obj = sudo_url
- try:
- # django 1.10 and greater can't resolve the string 'sudo.views.sudo' to a URL
- # https://docs.djangoproject.com/en/1.10/releases/1.10/#removed-features-1-10
- sudo_obj = import_string(sudo_obj)
- except (ImportError, ImproperlyConfigured):
- pass # wasn't a dotted path
- sudo_url_parts = list(urlparse(resolve_url(sudo_obj)))
- querystring = QueryDict(sudo_url_parts[4], mutable=True)
- querystring[REDIRECT_FIELD_NAME] = next_url
- sudo_url_parts[4] = querystring.urlencode(safe="/")
- return HttpResponseRedirect(urlunparse(sudo_url_parts))
|