Compare commits

..

6 Commits

Author SHA1 Message Date
pgjones eb8cfa9bf8
Utilise the new pallets actions
This should allow for a large reduction in duplicated action code
across the pallet's repos.
2025-03-29 15:19:33 -07:00
David Lord f61172b8dd
Merge branch 'stable' 2025-01-05 09:10:00 -08:00
David Lord 959052fb8d
use global contributing guide
Remove the per-project files so we don't have to
keep them in sync. GitHub's UI links to everything
except the contributing guide, so add a section
about that to the readme.

(cherry picked from commit 60a11a730e)
2025-01-05 09:09:33 -08:00
David Lord 5b525e9797
markdown formatting
(cherry picked from commit 6b361ce06b)
2025-01-05 09:09:32 -08:00
David Lord 60a11a730e
use global contributing guide
Remove the per-project files so we don't have to
keep them in sync. GitHub's UI links to everything
except the contributing guide, so add a section
about that to the readme.
2025-01-05 09:02:41 -08:00
David Lord 6b361ce06b
markdown formatting 2025-01-05 09:01:49 -08:00
7 changed files with 225 additions and 548 deletions

View File

@ -3,9 +3,9 @@ contact_links:
- name: Security issue
url: https://github.com/pallets/flask/security/advisories/new
about: Do not report security issues publicly. Create a private advisory.
- name: Questions
- name: Questions on GitHub Discussions
url: https://github.com/pallets/flask/discussions/
about: Ask questions about your own code on the Discussions tab.
- name: Questions on
- name: Questions on Discord
url: https://discord.gg/pallets
about: Ask questions about your own code on our Discord chat.

View File

@ -1,76 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at report@palletsprojects.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

View File

@ -1,238 +0,0 @@
How to contribute to Flask
==========================
Thank you for considering contributing to Flask!
Support questions
-----------------
Please don't use the issue tracker for this. The issue tracker is a tool
to address bugs and feature requests in Flask itself. Use one of the
following resources for questions about using Flask or issues with your
own code:
- The ``#questions`` channel on our Discord chat:
https://discord.gg/pallets
- Ask on `Stack Overflow`_. Search with Google first using:
``site:stackoverflow.com flask {search term, exception message, etc.}``
- Ask on our `GitHub Discussions`_ for long term discussion or larger
questions.
.. _Stack Overflow: https://stackoverflow.com/questions/tagged/flask?tab=Frequent
.. _GitHub Discussions: https://github.com/pallets/flask/discussions
Reporting issues
----------------
Include the following information in your post:
- Describe what you expected to happen.
- If possible, include a `minimal reproducible example`_ to help us
identify the issue. This also helps check that the issue is not with
your own code.
- Describe what actually happened. Include the full traceback if there
was an exception.
- List your Python and Flask versions. If possible, check if this
issue is already fixed in the latest releases or the latest code in
the repository.
.. _minimal reproducible example: https://stackoverflow.com/help/minimal-reproducible-example
Submitting patches
------------------
If there is not an open issue for what you want to submit, prefer
opening one for discussion before working on a PR. You can work on any
issue that doesn't have an open PR linked to it or a maintainer assigned
to it. These show up in the sidebar. No need to ask if you can work on
an issue that interests you.
Include the following in your patch:
- Use `Black`_ to format your code. This and other tools will run
automatically if you install `pre-commit`_ using the instructions
below.
- Include tests if your patch adds or changes code. Make sure the test
fails without your patch.
- Update any relevant docs pages and docstrings. Docs pages and
docstrings should be wrapped at 72 characters.
- Add an entry in ``CHANGES.rst``. Use the same style as other
entries. Also include ``.. versionchanged::`` inline changelogs in
relevant docstrings.
.. _Black: https://black.readthedocs.io
.. _pre-commit: https://pre-commit.com
First time setup using GitHub Codespaces
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
`GitHub Codespaces`_ creates a development environment that is already set up for the
project. By default it opens in Visual Studio Code for the Web, but this can
be changed in your GitHub profile settings to use Visual Studio Code or JetBrains
PyCharm on your local computer.
- Make sure you have a `GitHub account`_.
- From the project's repository page, click the green "Code" button and then "Create
codespace on main".
- The codespace will be set up, then Visual Studio Code will open. However, you'll
need to wait a bit longer for the Python extension to be installed. You'll know it's
ready when the terminal at the bottom shows that the virtualenv was activated.
- Check out a branch and `start coding`_.
.. _GitHub Codespaces: https://docs.github.com/en/codespaces
.. _devcontainer: https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers
First time setup in your local environment
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Make sure you have a `GitHub account`_.
- Download and install the `latest version of git`_.
- Configure git with your `username`_ and `email`_.
.. code-block:: text
$ git config --global user.name 'your name'
$ git config --global user.email 'your email'
- Fork Flask to your GitHub account by clicking the `Fork`_ button.
- `Clone`_ your fork locally, replacing ``your-username`` in the command below with
your actual username.
.. code-block:: text
$ git clone https://github.com/your-username/flask
$ cd flask
- Create a virtualenv. Use the latest version of Python.
- Linux/macOS
.. code-block:: text
$ python3 -m venv .venv
$ . .venv/bin/activate
- Windows
.. code-block:: text
> py -3 -m venv .venv
> .venv\Scripts\activate
- Install the development dependencies, then install Flask in editable mode.
.. code-block:: text
$ python -m pip install -U pip
$ pip install -r requirements/dev.txt && pip install -e .
- Install the pre-commit hooks.
.. code-block:: text
$ pre-commit install --install-hooks
.. _GitHub account: https://github.com/join
.. _latest version of git: https://git-scm.com/downloads
.. _username: https://docs.github.com/en/github/using-git/setting-your-username-in-git
.. _email: https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/setting-your-commit-email-address
.. _Fork: https://github.com/pallets/flask/fork
.. _Clone: https://docs.github.com/en/github/getting-started-with-github/fork-a-repo#step-2-create-a-local-clone-of-your-fork
.. _start coding:
Start coding
~~~~~~~~~~~~
- Create a branch to identify the issue you would like to work on. If you're
submitting a bug or documentation fix, branch off of the latest ".x" branch.
.. code-block:: text
$ git fetch origin
$ git checkout -b your-branch-name origin/2.0.x
If you're submitting a feature addition or change, branch off of the "main" branch.
.. code-block:: text
$ git fetch origin
$ git checkout -b your-branch-name origin/main
- Using your favorite editor, make your changes, `committing as you go`_.
- If you are in a codespace, you will be prompted to `create a fork`_ the first
time you make a commit. Enter ``Y`` to continue.
- Include tests that cover any code changes you make. Make sure the test fails without
your patch. Run the tests as described below.
- Push your commits to your fork on GitHub and `create a pull request`_. Link to the
issue being addressed with ``fixes #123`` in the pull request description.
.. code-block:: text
$ git push --set-upstream origin your-branch-name
.. _committing as you go: https://afraid-to-commit.readthedocs.io/en/latest/git/commandlinegit.html#commit-your-changes
.. _create a fork: https://docs.github.com/en/codespaces/developing-in-codespaces/using-source-control-in-your-codespace#about-automatic-forking
.. _create a pull request: https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request
.. _Running the tests:
Running the tests
~~~~~~~~~~~~~~~~~
Run the basic test suite with pytest.
.. code-block:: text
$ pytest
This runs the tests for the current environment, which is usually
sufficient. CI will run the full suite when you submit your pull
request. You can run the full test suite with tox if you don't want to
wait.
.. code-block:: text
$ tox
Running test coverage
~~~~~~~~~~~~~~~~~~~~~
Generating a report of lines that do not have test coverage can indicate
where to start contributing. Run ``pytest`` using ``coverage`` and
generate a report.
If you are using GitHub Codespaces, ``coverage`` is already installed
so you can skip the installation command.
.. code-block:: text
$ pip install coverage
$ coverage run -m pytest
$ coverage html
Open ``htmlcov/index.html`` in your browser to explore the report.
Read more about `coverage <https://coverage.readthedocs.io>`__.
Building the docs
~~~~~~~~~~~~~~~~~
Build the docs in the ``docs`` directory using Sphinx.
.. code-block:: text
$ cd docs
$ make html
Open ``_build/html/index.html`` in your browser to view the docs.
Read more about `Sphinx <https://www.sphinx-doc.org/en/stable/>`__.

View File

@ -1,9 +1,9 @@
# Flask
Flask is a lightweight [WSGI][] web application framework. It is designed
Flask is a lightweight [WSGI] web application framework. It is designed
to make getting started quick and easy, with the ability to scale up to
complex applications. It began as a simple wrapper around [Werkzeug][]
and [Jinja][], and has become one of the most popular Python web
complex applications. It began as a simple wrapper around [Werkzeug]
and [Jinja], and has become one of the most popular Python web
application frameworks.
Flask offers suggestions, but doesn't enforce any dependencies or
@ -15,7 +15,6 @@ community that make adding new functionality easy.
[Werkzeug]: https://werkzeug.palletsprojects.com/
[Jinja]: https://jinja.palletsprojects.com/
## A Simple Example
```python
@ -34,12 +33,19 @@ $ flask run
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```
## Donate
The Pallets organization develops and supports Flask and the libraries
it uses. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, [please
donate today][].
donate today].
[please donate today]: https://palletsprojects.com/donate
## Contributing
See our [detailed contributing documentation][contrib] for many ways to
contribute, including reporting issues, requesting features, asking or answering
questions, and making PRs.
[contrib]: https://palletsprojects.com/contributing/

View File

@ -1 +1,8 @@
.. include:: ../CONTRIBUTING.rst
Contributing
============
See the Pallets `detailed contributing documentation <_contrib>`_ for many ways
to contribute, including reporting issues, requesting features, asking or
answering questions, and making PRs.
.. _contrib: https://palletsprojects.com/contributing/

View File

@ -1,215 +0,0 @@
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"]
)

View File

@ -1,28 +1,122 @@
from __future__ import annotations
import collections.abc as c
import hashlib
import typing as t
from collections.abc import MutableMapping
from datetime import datetime
from datetime import timezone
from itsdangerous import BadSignature
from itsdangerous import URLSafeTimedSerializer
from werkzeug.datastructures import CallbackDict
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
import typing_extensions as te
from .app import Flask
from .wrappers import Request
from .wrappers import Response
class SessionInterface(SansioSessionInterface):
"""The basic interface you have to implement in order to replace
the default session interface. 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.
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:
"""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
provide a dictionary like interface plus the properties and methods
@ -52,9 +146,21 @@ class SessionInterface(SansioSessionInterface):
begin and end processing.
.. 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:
"""Creates a null session which acts as a replacement object if the
real session support could not be loaded due to a configuration
@ -67,6 +173,93 @@ class SessionInterface(SansioSessionInterface):
"""
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:
"""This is called at the beginning of each request, after
pushing the request context, before matching the URL.