mirror of https://github.com/pallets/flask.git
Compare commits
3 Commits
69b6a7cad0
...
def721cda1
Author | SHA1 | Date |
---|---|---|
|
def721cda1 | |
|
e6397e3d04 | |
|
028160e49f |
|
@ -24,28 +24,18 @@ jobs:
|
||||||
- {name: Minimum Versions, python: '3.12', tox: py-min}
|
- {name: Minimum Versions, python: '3.12', tox: py-min}
|
||||||
- {name: Development Versions, python: '3.9', tox: py-dev}
|
- {name: Development Versions, python: '3.9', tox: py-dev}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: pallets/actions/tox@5c46d4abb052877fa7e84db0ceec21b33673559e
|
||||||
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
||||||
with:
|
with:
|
||||||
|
environment: ${{ format('py{0}', matrix.python) }}
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
allow-prereleases: true
|
|
||||||
cache: pip
|
|
||||||
cache-dependency-path: requirements*/*.txt
|
|
||||||
- run: pip install tox
|
|
||||||
- run: tox run -e ${{ matrix.tox || format('py{0}', matrix.python) }}
|
|
||||||
typing:
|
typing:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: pallets/actions/tox@5c46d4abb052877fa7e84db0ceec21b33673559e
|
||||||
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
||||||
with:
|
with:
|
||||||
|
environment: 'typing'
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
cache: pip
|
workflow:
|
||||||
cache-dependency-path: requirements*/*.txt
|
runs-on: ubuntu-latest
|
||||||
- name: cache mypy
|
steps:
|
||||||
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
|
- uses: pallets/actions/zizmor@5c46d4abb052877fa7e84db0ceec21b33673559e
|
||||||
with:
|
|
||||||
path: ./.mypy_cache
|
|
||||||
key: mypy|${{ hashFiles('pyproject.toml') }}
|
|
||||||
- run: pip install tox
|
|
||||||
- run: tox run -e typing
|
|
||||||
|
|
|
@ -0,0 +1,215 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import collections.abc as c
|
||||||
|
import typing as t
|
||||||
|
from abc import ABCMeta
|
||||||
|
from collections.abc import MutableMapping
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timezone
|
||||||
|
|
||||||
|
from werkzeug.datastructures import CallbackDict
|
||||||
|
|
||||||
|
from .app import App
|
||||||
|
|
||||||
|
if t.TYPE_CHECKING: # pragma: no cover
|
||||||
|
import typing_extensions as te
|
||||||
|
|
||||||
|
|
||||||
|
class SessionMixin(MutableMapping[str, t.Any]):
|
||||||
|
"""Expands a basic dictionary with session attributes."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def permanent(self) -> bool:
|
||||||
|
"""This reflects the ``'_permanent'`` key in the dict."""
|
||||||
|
return self.get("_permanent", False)
|
||||||
|
|
||||||
|
@permanent.setter
|
||||||
|
def permanent(self, value: bool) -> None:
|
||||||
|
self["_permanent"] = bool(value)
|
||||||
|
|
||||||
|
#: Some implementations can detect whether a session is newly
|
||||||
|
#: created, but that is not guaranteed. Use with caution. The mixin
|
||||||
|
# default is hard-coded ``False``.
|
||||||
|
new = False
|
||||||
|
|
||||||
|
#: Some implementations can detect changes to the session and set
|
||||||
|
#: this when that happens. The mixin default is hard coded to
|
||||||
|
#: ``True``.
|
||||||
|
modified = True
|
||||||
|
|
||||||
|
#: Some implementations can detect when session data is read or
|
||||||
|
#: written and set this when that happens. The mixin default is hard
|
||||||
|
#: coded to ``True``.
|
||||||
|
accessed = True
|
||||||
|
|
||||||
|
|
||||||
|
class SecureCookieSession(CallbackDict[str, t.Any], SessionMixin):
|
||||||
|
"""Base class for sessions based on signed cookies.
|
||||||
|
|
||||||
|
This session backend will set the :attr:`modified` and
|
||||||
|
:attr:`accessed` attributes. It cannot reliably track whether a
|
||||||
|
session is new (vs. empty), so :attr:`new` remains hard coded to
|
||||||
|
``False``.
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: When data is changed, this is set to ``True``. Only the session
|
||||||
|
#: dictionary itself is tracked; if the session contains mutable
|
||||||
|
#: data (for example a nested dict) then this must be set to
|
||||||
|
#: ``True`` manually when modifying that data. The session cookie
|
||||||
|
#: will only be written to the response if this is ``True``.
|
||||||
|
modified = False
|
||||||
|
|
||||||
|
#: When data is read or written, this is set to ``True``. Used by
|
||||||
|
# :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie``
|
||||||
|
#: header, which allows caching proxies to cache different pages for
|
||||||
|
#: different users.
|
||||||
|
accessed = False
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
initial: c.Mapping[str, t.Any] | c.Iterable[tuple[str, t.Any]] | None = None,
|
||||||
|
) -> None:
|
||||||
|
def on_update(self: te.Self) -> None:
|
||||||
|
self.modified = True
|
||||||
|
self.accessed = True
|
||||||
|
|
||||||
|
super().__init__(initial, on_update)
|
||||||
|
|
||||||
|
def __getitem__(self, key: str) -> t.Any:
|
||||||
|
self.accessed = True
|
||||||
|
return super().__getitem__(key)
|
||||||
|
|
||||||
|
def get(self, key: str, default: t.Any = None) -> t.Any:
|
||||||
|
self.accessed = True
|
||||||
|
return super().get(key, default)
|
||||||
|
|
||||||
|
def setdefault(self, key: str, default: t.Any = None) -> t.Any:
|
||||||
|
self.accessed = True
|
||||||
|
return super().setdefault(key, default)
|
||||||
|
|
||||||
|
|
||||||
|
class NullSession(SecureCookieSession):
|
||||||
|
"""Class used to generate nicer error messages if sessions are not
|
||||||
|
available. Will still allow read-only access to the empty session
|
||||||
|
but fail on setting.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn:
|
||||||
|
raise RuntimeError(
|
||||||
|
"The session is unavailable because no secret "
|
||||||
|
"key was set. Set the secret_key on the "
|
||||||
|
"application to something unique and secret."
|
||||||
|
)
|
||||||
|
|
||||||
|
__setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail # type: ignore # noqa: B950
|
||||||
|
del _fail
|
||||||
|
|
||||||
|
|
||||||
|
class SessionInterface(metaclass=ABCMeta): # noqa: B024
|
||||||
|
"""This is a SansIO abstract base class used by Flask and Quart to
|
||||||
|
then define thebasic interface to implement in order to replace
|
||||||
|
the default session interface of the frameworks.
|
||||||
|
|
||||||
|
.. versionadded:: 3.2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: :meth:`make_null_session` will look here for the class that should
|
||||||
|
#: be created when a null session is requested. Likewise the
|
||||||
|
#: :meth:`is_null_session` method will perform a typecheck against
|
||||||
|
#: this type.
|
||||||
|
null_session_class = NullSession
|
||||||
|
|
||||||
|
#: A flag that indicates if the session interface is pickle based.
|
||||||
|
#: This can be used by Flask extensions to make a decision in regards
|
||||||
|
#: to how to deal with the session object.
|
||||||
|
#:
|
||||||
|
#: .. versionadded:: 0.10
|
||||||
|
pickle_based = False
|
||||||
|
|
||||||
|
def is_null_session(self, obj: object) -> bool:
|
||||||
|
"""Checks if a given object is a null session. Null sessions are
|
||||||
|
not asked to be saved.
|
||||||
|
|
||||||
|
This checks if the object is an instance of :attr:`null_session_class`
|
||||||
|
by default.
|
||||||
|
"""
|
||||||
|
return isinstance(obj, self.null_session_class)
|
||||||
|
|
||||||
|
def get_cookie_name(self, app: App) -> str:
|
||||||
|
"""The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``."""
|
||||||
|
return app.config["SESSION_COOKIE_NAME"] # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
def get_cookie_domain(self, app: App) -> str | None:
|
||||||
|
"""The value of the ``Domain`` parameter on the session cookie. If not set,
|
||||||
|
browsers will only send the cookie to the exact domain it was set from.
|
||||||
|
Otherwise, they will send it to any subdomain of the given value as well.
|
||||||
|
|
||||||
|
Uses the :data:`SESSION_COOKIE_DOMAIN` config.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.3
|
||||||
|
Not set by default, does not fall back to ``SERVER_NAME``.
|
||||||
|
"""
|
||||||
|
return app.config["SESSION_COOKIE_DOMAIN"] # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
def get_cookie_path(self, app: App) -> str:
|
||||||
|
"""Returns the path for which the cookie should be valid. The
|
||||||
|
default implementation uses the value from the ``SESSION_COOKIE_PATH``
|
||||||
|
config var if it's set, and falls back to ``APPLICATION_ROOT`` or
|
||||||
|
uses ``/`` if it's ``None``.
|
||||||
|
"""
|
||||||
|
return app.config["SESSION_COOKIE_PATH"] or app.config["APPLICATION_ROOT"] # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
def get_cookie_httponly(self, app: App) -> bool:
|
||||||
|
"""Returns True if the session cookie should be httponly. This
|
||||||
|
currently just returns the value of the ``SESSION_COOKIE_HTTPONLY``
|
||||||
|
config var.
|
||||||
|
"""
|
||||||
|
return app.config["SESSION_COOKIE_HTTPONLY"] # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
def get_cookie_secure(self, app: App) -> bool:
|
||||||
|
"""Returns True if the cookie should be secure. This currently
|
||||||
|
just returns the value of the ``SESSION_COOKIE_SECURE`` setting.
|
||||||
|
"""
|
||||||
|
return app.config["SESSION_COOKIE_SECURE"] # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
def get_cookie_samesite(self, app: App) -> str | None:
|
||||||
|
"""Return ``'Strict'`` or ``'Lax'`` if the cookie should use the
|
||||||
|
``SameSite`` attribute. This currently just returns the value of
|
||||||
|
the :data:`SESSION_COOKIE_SAMESITE` setting.
|
||||||
|
"""
|
||||||
|
return app.config["SESSION_COOKIE_SAMESITE"] # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
def get_cookie_partitioned(self, app: App) -> bool:
|
||||||
|
"""Returns True if the cookie should be partitioned. By default, uses
|
||||||
|
the value of :data:`SESSION_COOKIE_PARTITIONED`.
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
"""
|
||||||
|
return app.config["SESSION_COOKIE_PARTITIONED"] # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
def get_expiration_time(self, app: App, session: SessionMixin) -> datetime | None:
|
||||||
|
"""A helper method that returns an expiration date for the session
|
||||||
|
or ``None`` if the session is linked to the browser session. The
|
||||||
|
default implementation returns now + the permanent session
|
||||||
|
lifetime configured on the application.
|
||||||
|
"""
|
||||||
|
if session.permanent:
|
||||||
|
return datetime.now(timezone.utc) + app.permanent_session_lifetime
|
||||||
|
return None
|
||||||
|
|
||||||
|
def should_set_cookie(self, app: App, session: SessionMixin) -> bool:
|
||||||
|
"""Used by session backends to determine if a ``Set-Cookie`` header
|
||||||
|
should be set for this session cookie for this response. If the session
|
||||||
|
has been modified, the cookie is set. If the session is permanent and
|
||||||
|
the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the cookie is
|
||||||
|
always set.
|
||||||
|
|
||||||
|
This check is usually skipped if the session was deleted.
|
||||||
|
|
||||||
|
.. versionadded:: 0.11
|
||||||
|
"""
|
||||||
|
|
||||||
|
return session.modified or (
|
||||||
|
session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"]
|
||||||
|
)
|
|
@ -1,122 +1,28 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import collections.abc as c
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import typing as t
|
import typing as t
|
||||||
from collections.abc import MutableMapping
|
|
||||||
from datetime import datetime
|
|
||||||
from datetime import timezone
|
|
||||||
|
|
||||||
from itsdangerous import BadSignature
|
from itsdangerous import BadSignature
|
||||||
from itsdangerous import URLSafeTimedSerializer
|
from itsdangerous import URLSafeTimedSerializer
|
||||||
from werkzeug.datastructures import CallbackDict
|
|
||||||
|
|
||||||
from .json.tag import TaggedJSONSerializer
|
from .json.tag import TaggedJSONSerializer
|
||||||
|
from .sansio.sessions import NullSession as NullSession
|
||||||
|
from .sansio.sessions import SecureCookieSession as SecureCookieSession
|
||||||
|
from .sansio.sessions import SessionInterface as SansioSessionInterface
|
||||||
|
from .sansio.sessions import SessionMixin as SessionMixin
|
||||||
|
|
||||||
if t.TYPE_CHECKING: # pragma: no cover
|
if t.TYPE_CHECKING: # pragma: no cover
|
||||||
import typing_extensions as te
|
|
||||||
|
|
||||||
from .app import Flask
|
from .app import Flask
|
||||||
from .wrappers import Request
|
from .wrappers import Request
|
||||||
from .wrappers import Response
|
from .wrappers import Response
|
||||||
|
|
||||||
|
|
||||||
class SessionMixin(MutableMapping[str, t.Any]):
|
class SessionInterface(SansioSessionInterface):
|
||||||
"""Expands a basic dictionary with session attributes."""
|
"""The basic interface you have to implement in order to replace
|
||||||
|
the default session interface. The only methods you have to
|
||||||
@property
|
implement are :meth:`open_session` and :meth:`save_session`, the
|
||||||
def permanent(self) -> bool:
|
others have useful defaults which you don't need to change.
|
||||||
"""This reflects the ``'_permanent'`` key in the dict."""
|
|
||||||
return self.get("_permanent", False)
|
|
||||||
|
|
||||||
@permanent.setter
|
|
||||||
def permanent(self, value: bool) -> None:
|
|
||||||
self["_permanent"] = bool(value)
|
|
||||||
|
|
||||||
#: Some implementations can detect whether a session is newly
|
|
||||||
#: created, but that is not guaranteed. Use with caution. The mixin
|
|
||||||
# default is hard-coded ``False``.
|
|
||||||
new = False
|
|
||||||
|
|
||||||
#: Some implementations can detect changes to the session and set
|
|
||||||
#: this when that happens. The mixin default is hard coded to
|
|
||||||
#: ``True``.
|
|
||||||
modified = True
|
|
||||||
|
|
||||||
#: Some implementations can detect when session data is read or
|
|
||||||
#: written and set this when that happens. The mixin default is hard
|
|
||||||
#: coded to ``True``.
|
|
||||||
accessed = True
|
|
||||||
|
|
||||||
|
|
||||||
class SecureCookieSession(CallbackDict[str, t.Any], SessionMixin):
|
|
||||||
"""Base class for sessions based on signed cookies.
|
|
||||||
|
|
||||||
This session backend will set the :attr:`modified` and
|
|
||||||
:attr:`accessed` attributes. It cannot reliably track whether a
|
|
||||||
session is new (vs. empty), so :attr:`new` remains hard coded to
|
|
||||||
``False``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#: When data is changed, this is set to ``True``. Only the session
|
|
||||||
#: dictionary itself is tracked; if the session contains mutable
|
|
||||||
#: data (for example a nested dict) then this must be set to
|
|
||||||
#: ``True`` manually when modifying that data. The session cookie
|
|
||||||
#: will only be written to the response if this is ``True``.
|
|
||||||
modified = False
|
|
||||||
|
|
||||||
#: When data is read or written, this is set to ``True``. Used by
|
|
||||||
# :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie``
|
|
||||||
#: header, which allows caching proxies to cache different pages for
|
|
||||||
#: different users.
|
|
||||||
accessed = False
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
initial: c.Mapping[str, t.Any] | c.Iterable[tuple[str, t.Any]] | None = None,
|
|
||||||
) -> None:
|
|
||||||
def on_update(self: te.Self) -> None:
|
|
||||||
self.modified = True
|
|
||||||
self.accessed = True
|
|
||||||
|
|
||||||
super().__init__(initial, on_update)
|
|
||||||
|
|
||||||
def __getitem__(self, key: str) -> t.Any:
|
|
||||||
self.accessed = True
|
|
||||||
return super().__getitem__(key)
|
|
||||||
|
|
||||||
def get(self, key: str, default: t.Any = None) -> t.Any:
|
|
||||||
self.accessed = True
|
|
||||||
return super().get(key, default)
|
|
||||||
|
|
||||||
def setdefault(self, key: str, default: t.Any = None) -> t.Any:
|
|
||||||
self.accessed = True
|
|
||||||
return super().setdefault(key, default)
|
|
||||||
|
|
||||||
|
|
||||||
class NullSession(SecureCookieSession):
|
|
||||||
"""Class used to generate nicer error messages if sessions are not
|
|
||||||
available. Will still allow read-only access to the empty session
|
|
||||||
but fail on setting.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn:
|
|
||||||
raise RuntimeError(
|
|
||||||
"The session is unavailable because no secret "
|
|
||||||
"key was set. Set the secret_key on the "
|
|
||||||
"application to something unique and secret."
|
|
||||||
)
|
|
||||||
|
|
||||||
__setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail # type: ignore # noqa: B950
|
|
||||||
del _fail
|
|
||||||
|
|
||||||
|
|
||||||
class SessionInterface:
|
|
||||||
"""The basic interface you have to implement in order to replace the
|
|
||||||
default session interface which uses werkzeug's securecookie
|
|
||||||
implementation. The only methods you have to implement are
|
|
||||||
:meth:`open_session` and :meth:`save_session`, the others have
|
|
||||||
useful defaults which you don't need to change.
|
|
||||||
|
|
||||||
The session object returned by the :meth:`open_session` method has to
|
The session object returned by the :meth:`open_session` method has to
|
||||||
provide a dictionary like interface plus the properties and methods
|
provide a dictionary like interface plus the properties and methods
|
||||||
|
@ -146,21 +52,9 @@ class SessionInterface:
|
||||||
begin and end processing.
|
begin and end processing.
|
||||||
|
|
||||||
.. versionadded:: 0.8
|
.. versionadded:: 0.8
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#: :meth:`make_null_session` will look here for the class that should
|
|
||||||
#: be created when a null session is requested. Likewise the
|
|
||||||
#: :meth:`is_null_session` method will perform a typecheck against
|
|
||||||
#: this type.
|
|
||||||
null_session_class = NullSession
|
|
||||||
|
|
||||||
#: A flag that indicates if the session interface is pickle based.
|
|
||||||
#: This can be used by Flask extensions to make a decision in regards
|
|
||||||
#: to how to deal with the session object.
|
|
||||||
#:
|
|
||||||
#: .. versionadded:: 0.10
|
|
||||||
pickle_based = False
|
|
||||||
|
|
||||||
def make_null_session(self, app: Flask) -> NullSession:
|
def make_null_session(self, app: Flask) -> NullSession:
|
||||||
"""Creates a null session which acts as a replacement object if the
|
"""Creates a null session which acts as a replacement object if the
|
||||||
real session support could not be loaded due to a configuration
|
real session support could not be loaded due to a configuration
|
||||||
|
@ -173,93 +67,6 @@ class SessionInterface:
|
||||||
"""
|
"""
|
||||||
return self.null_session_class()
|
return self.null_session_class()
|
||||||
|
|
||||||
def is_null_session(self, obj: object) -> bool:
|
|
||||||
"""Checks if a given object is a null session. Null sessions are
|
|
||||||
not asked to be saved.
|
|
||||||
|
|
||||||
This checks if the object is an instance of :attr:`null_session_class`
|
|
||||||
by default.
|
|
||||||
"""
|
|
||||||
return isinstance(obj, self.null_session_class)
|
|
||||||
|
|
||||||
def get_cookie_name(self, app: Flask) -> str:
|
|
||||||
"""The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``."""
|
|
||||||
return app.config["SESSION_COOKIE_NAME"] # type: ignore[no-any-return]
|
|
||||||
|
|
||||||
def get_cookie_domain(self, app: Flask) -> str | None:
|
|
||||||
"""The value of the ``Domain`` parameter on the session cookie. If not set,
|
|
||||||
browsers will only send the cookie to the exact domain it was set from.
|
|
||||||
Otherwise, they will send it to any subdomain of the given value as well.
|
|
||||||
|
|
||||||
Uses the :data:`SESSION_COOKIE_DOMAIN` config.
|
|
||||||
|
|
||||||
.. versionchanged:: 2.3
|
|
||||||
Not set by default, does not fall back to ``SERVER_NAME``.
|
|
||||||
"""
|
|
||||||
return app.config["SESSION_COOKIE_DOMAIN"] # type: ignore[no-any-return]
|
|
||||||
|
|
||||||
def get_cookie_path(self, app: Flask) -> str:
|
|
||||||
"""Returns the path for which the cookie should be valid. The
|
|
||||||
default implementation uses the value from the ``SESSION_COOKIE_PATH``
|
|
||||||
config var if it's set, and falls back to ``APPLICATION_ROOT`` or
|
|
||||||
uses ``/`` if it's ``None``.
|
|
||||||
"""
|
|
||||||
return app.config["SESSION_COOKIE_PATH"] or app.config["APPLICATION_ROOT"] # type: ignore[no-any-return]
|
|
||||||
|
|
||||||
def get_cookie_httponly(self, app: Flask) -> bool:
|
|
||||||
"""Returns True if the session cookie should be httponly. This
|
|
||||||
currently just returns the value of the ``SESSION_COOKIE_HTTPONLY``
|
|
||||||
config var.
|
|
||||||
"""
|
|
||||||
return app.config["SESSION_COOKIE_HTTPONLY"] # type: ignore[no-any-return]
|
|
||||||
|
|
||||||
def get_cookie_secure(self, app: Flask) -> bool:
|
|
||||||
"""Returns True if the cookie should be secure. This currently
|
|
||||||
just returns the value of the ``SESSION_COOKIE_SECURE`` setting.
|
|
||||||
"""
|
|
||||||
return app.config["SESSION_COOKIE_SECURE"] # type: ignore[no-any-return]
|
|
||||||
|
|
||||||
def get_cookie_samesite(self, app: Flask) -> str | None:
|
|
||||||
"""Return ``'Strict'`` or ``'Lax'`` if the cookie should use the
|
|
||||||
``SameSite`` attribute. This currently just returns the value of
|
|
||||||
the :data:`SESSION_COOKIE_SAMESITE` setting.
|
|
||||||
"""
|
|
||||||
return app.config["SESSION_COOKIE_SAMESITE"] # type: ignore[no-any-return]
|
|
||||||
|
|
||||||
def get_cookie_partitioned(self, app: Flask) -> bool:
|
|
||||||
"""Returns True if the cookie should be partitioned. By default, uses
|
|
||||||
the value of :data:`SESSION_COOKIE_PARTITIONED`.
|
|
||||||
|
|
||||||
.. versionadded:: 3.1
|
|
||||||
"""
|
|
||||||
return app.config["SESSION_COOKIE_PARTITIONED"] # type: ignore[no-any-return]
|
|
||||||
|
|
||||||
def get_expiration_time(self, app: Flask, session: SessionMixin) -> datetime | None:
|
|
||||||
"""A helper method that returns an expiration date for the session
|
|
||||||
or ``None`` if the session is linked to the browser session. The
|
|
||||||
default implementation returns now + the permanent session
|
|
||||||
lifetime configured on the application.
|
|
||||||
"""
|
|
||||||
if session.permanent:
|
|
||||||
return datetime.now(timezone.utc) + app.permanent_session_lifetime
|
|
||||||
return None
|
|
||||||
|
|
||||||
def should_set_cookie(self, app: Flask, session: SessionMixin) -> bool:
|
|
||||||
"""Used by session backends to determine if a ``Set-Cookie`` header
|
|
||||||
should be set for this session cookie for this response. If the session
|
|
||||||
has been modified, the cookie is set. If the session is permanent and
|
|
||||||
the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the cookie is
|
|
||||||
always set.
|
|
||||||
|
|
||||||
This check is usually skipped if the session was deleted.
|
|
||||||
|
|
||||||
.. versionadded:: 0.11
|
|
||||||
"""
|
|
||||||
|
|
||||||
return session.modified or (
|
|
||||||
session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def open_session(self, app: Flask, request: Request) -> SessionMixin | None:
|
def open_session(self, app: Flask, request: Request) -> SessionMixin | None:
|
||||||
"""This is called at the beginning of each request, after
|
"""This is called at the beginning of each request, after
|
||||||
pushing the request context, before matching the URL.
|
pushing the request context, before matching the URL.
|
||||||
|
|
Loading…
Reference in New Issue