Beispiel #1
0
 def __call__(self, scope: Scope) -> NoReturn:
     # Get the path
     path = scope.get("path_remaining", scope.get("path", None))
     if path is None:
         raise ValueError(
             "No 'path' key in connection scope, cannot route URLs")
     # Remove leading / to match Django's handling
     path = path.lstrip("/")
     # Run through the routes we have until one matches
     for route in self.routes:
         try:
             match = route_pattern_match(route, path)
             if match:
                 new_path, args, kwargs = match
                 # Add args or kwargs into the scope
                 outer = scope.get("url_route", {})
                 return route.callback(
                     dict(
                         scope,
                         path_remaining=new_path,
                         url_route={
                             "args": outer.get("args", ()) + args,
                             "kwargs": {
                                 **outer.get("kwargs", {}),
                                 **kwargs
                             },
                         },
                     ))
         except Resolver404:
             pass
     else:
         if "path_remaining" in scope:
             raise Resolver404("No route found for path %r." % path)
         # We are the outermost URLRouter
         raise ValueError("No route found for path %r." % path)
Beispiel #2
0
    def set_cookie(
        cls,
        message: Scope,
        key: str,
        value: str = "",
        max_age: Optional[int] = None,
        expires: Optional[Union[datetime, str]] = None,
        path: str = "/",
        domain: Optional[str] = None,
        secure: bool = False,
        httponly: bool = False,
    ) -> NoReturn:
        """
        Sets a cookie in the passed HTTP response message.

        ``expires`` can be:
        - a string in the correct format,
        - a naive ``datetime.datetime`` object in UTC,
        - an aware ``datetime.datetime`` object in any time zone.
        If it is a ``datetime.datetime`` object then ``max_age`` will be calculated.
        """
        value = force_str(value)
        cookies = SimpleCookie()
        cookies[key] = value
        if expires is not None:
            if isinstance(expires, datetime):
                if timezone.is_aware(expires):
                    expires = timezone.make_naive(expires, timezone.utc)
                delta = expires - expires.utcnow()
                # Add one second so the date matches exactly (a fraction of
                # time gets lost between converting to a timedelta and
                # then the date string).
                delta = delta + timedelta(seconds=1)
                # Just set max_age - the max_age logic will set expires.
                expires = None
                max_age = max(0, delta.days * 86400 + delta.seconds)
            else:
                cookies[key]["expires"] = expires
        else:
            cookies[key]["expires"] = ""
        if max_age is not None:
            cookies[key]["max-age"] = max_age
            # IE requires expires, so set it if hasn't been already.
            if not expires:
                cookies[key]["expires"] = http_date(time.time() + max_age)
        if path is not None:
            cookies[key]["path"] = path
        if domain is not None:
            cookies[key]["domain"] = domain
        if secure:
            cookies[key]["secure"] = True
        if httponly:
            cookies[key]["httponly"] = True
        # Write out the cookies to the response
        for c in cookies.values():
            message.setdefault("headers", []).append(
                (b"Set-Cookie", bytes(c.output(header=""), encoding="utf-8")))
Beispiel #3
0
 def get_application(self, options: Scope):
     """
     Returns the static files serving application wrapping the default application,
     if static files should be served. Otherwise just returns the default
     handler.
     """
     staticfiles_installed = apps.is_installed("django.contrib.staticfiles")
     use_static_handler = options.get("use_static_handler",
                                      staticfiles_installed)
     insecure_serving = options.get("insecure_serving", False)
     if use_static_handler and (settings.DEBUG or insecure_serving):
         return StaticFilesWrapper(get_default_application())
     else:
         return get_default_application()
Beispiel #4
0
 async def send(self, message: Scope) -> Awaitable[Any]:
     """
     Overridden send that also does session saves/cookies.
     """
     # Only save session if we're the outermost session middleware
     if self.activated:
         modified = self.scope["session"].modified
         empty = self.scope["session"].is_empty()
         # If this is a message type that we want to save on, and there's
         # changed data, save it. We also save if it's empty as we might
         # not be able to send a cookie-delete along with this message.
         if (message["type"] in self.middleware.save_message_types
                 and message.get("status", 200) != 500
                 and (modified or settings.SESSION_SAVE_EVERY_REQUEST)):
             await database_sync_to_async(self.save_session)()
             # If this is a message type that can transport cookies back to the
             # client, then do so.
             if message[
                     "type"] in self.middleware.cookie_response_message_types:
                 if empty:
                     # Delete cookie if it's set
                     if settings.SESSION_COOKIE_NAME in self.scope[
                             "cookies"]:
                         CookieMiddleware.delete_cookie(
                             message,
                             settings.SESSION_COOKIE_NAME,
                             path=settings.SESSION_COOKIE_PATH,
                             domain=settings.SESSION_COOKIE_DOMAIN,
                         )
                 else:
                     # Get the expiry data
                     if self.scope["session"].get_expire_at_browser_close():
                         max_age = None
                         expires = None
                     else:
                         max_age = self.scope["session"].get_expiry_age()
                         expires_time = time.time() + max_age
                         expires = http_date(expires_time)
                     # Set the cookie
                     CookieMiddleware.set_cookie(
                         message,
                         self.middleware.cookie_name,
                         self.scope["session"].session_key,
                         max_age=max_age,
                         expires=expires,
                         domain=settings.SESSION_COOKIE_DOMAIN,
                         path=settings.SESSION_COOKIE_PATH,
                         secure=settings.SESSION_COOKIE_SECURE or None,
                         httponly=settings.SESSION_COOKIE_HTTPONLY or None,
                     )
     # Pass up the send
     return await self.real_send(message)
Beispiel #5
0
 async def http_request(self, message: Scope) -> None:
     """
     Async entrypoint - concatenates body fragments and hands off control
     to ``self.handle`` when the body has been completely received.
     """
     if "body" in message:
         self.body.append(message["body"])
     if not message.get("more_body"):
         try:
             await self.handle(b"".join(self.body))
         finally:
             await self.disconnect()
             raise StopConsumer()
Beispiel #6
0
def login(scope: Scope,
          user: Optional[Union[AbstractBaseUser, AnonymousUser]],
          backend=None) -> None:
    """
    Persist a user id and a backend in the request.
    This way a user doesn't have to re-authenticate on every request.
    Note that data set during the anonymous session is retained when the user logs in.
    """
    if "session" not in scope:
        raise ValueError(
            "Cannot find session in scope. You should wrap your consumer in SessionMiddleware."
        )
    session = scope["session"]
    session_auth_hash = ""
    if user is None:
        user = scope.get("user", None)
    if user is None:
        raise ValueError(
            "User must be passed as an argument or must be present in the scope."
        )
    if hasattr(user, "get_session_auth_hash"):
        session_auth_hash = user.get_session_auth_hash()
    if SESSION_KEY in session:
        if _get_user_session_key(session) != user.pk or (
                session_auth_hash and not constant_time_compare(
                    session.get(HASH_SESSION_KEY, ""), session_auth_hash)):
            # To avoid reusing another user's session, create a new, empty
            # session if the existing session corresponds to a different
            # authenticated user.
            session.flush()
    else:
        session.cycle_key()
    try:
        backend = backend or user.backend
    except AttributeError:
        backends = _get_backends(return_tuples=True)
        if len(backends) == 1:
            _, backend = backends[0]
        else:
            raise ValueError(
                "You have multiple authentication backends configured and therefore must provide the `backend` "
                "argument or set the `backend` attribute on the user.")
    session[SESSION_KEY] = user._meta.pk.value_to_string(user)
    session[BACKEND_SESSION_KEY] = backend
    session[HASH_SESSION_KEY] = session_auth_hash
    scope["user"] = user
    # note this does not reset the CSRF_COOKIE/Token
    user_logged_in.send(sender=user.__class__, request=None, user=user)
Beispiel #7
0
 def __call__(self, scope: Scope):
     # Check this actually has headers. They're a required scope key for HTTP and WS.
     if "headers" not in scope:
         raise ValueError(
             "CookieMiddleware was passed a scope that did not have a headers key "
             +
             "(make sure it is only passed HTTP or WebSocket connections)")
     # Go through headers to find the cookie one
     for name, value in scope.get("headers", []):
         if name == b"cookie":
             cookies = parse_cookie(value.decode("ascii"))
             break
     else:
         # No cookie header found - add an empty default.
         cookies = {}
     # Return inner application
     return self.inner(dict(scope, cookies=cookies))
Beispiel #8
0
 def __call__(self, scope: Scope):
     # Make sure the scope is of type websocket
     if scope["type"] != "websocket":
         raise ValueError(
             "You cannot use OriginValidator on a non-WebSocket connection")
     # Extract the Origin header
     parsed_origin = None
     for header_name, header_value in scope.get("headers", []):
         if header_name == b"origin":
             try:
                 # Set ResultParse
                 parsed_origin = urlparse(header_value.decode("ascii"))
             except UnicodeDecodeError:
                 pass
     # Check to see if the origin header is valid
     if self.valid_origin(parsed_origin):
         # Pass control to the application
         return self.application(scope)
     else:
         # Deny the connection
         return WebsocketDenier(scope)
Beispiel #9
0
def logout(scope: Scope) -> None:
    """
    Remove the authenticated user's ID from the request and flush their session data.
    """
    if "session" not in scope:
        raise ValueError(
            "Login cannot find session in scope. You should wrap your consumer in SessionMiddleware."
        )
    session = scope["session"]
    # Dispatch the signal before the user is logged out so the receivers have a
    # chance to find out *who* logged out.
    user = scope.get("user", None)
    if hasattr(user, "is_authenticated") and not user.is_authenticated:
        user = None
    if user is not None:
        user_logged_out.send(sender=user.__class__, request=None, user=user)
    # remember language choice saved to session
    language = session.get(LANGUAGE_SESSION_KEY)
    session.flush()
    if language is not None:
        session[LANGUAGE_SESSION_KEY] = language
    if "user" in scope:
        scope["user"] = AnonymousUser()