Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] main from pallets:main #270

Merged
merged 33 commits into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1d610e4
drop support for Python 3.8
davidism Oct 31, 2024
99ce7ed
drop support for Python 3.8 (#5623)
davidism Oct 31, 2024
227838c
no need for separate requirements-skip folder anymore
davidism Oct 31, 2024
39e7208
update dev dependencies
davidism Oct 31, 2024
8f37c82
update min dependencies
davidism Oct 31, 2024
62c56e0
update minimum dependencies (#5624)
davidism Oct 31, 2024
c7a5388
add config and docs for limits
davidism Nov 1, 2024
6f2014d
add config and docs for limits (#5626)
davidism Nov 1, 2024
9efc1eb
add SESSION_COOKIE_PARTITIONED config
davidism Jun 10, 2024
ce08bc7
add SESSION_COOKIE_PARTITIONED config (#5499)
davidism Nov 1, 2024
df201ed
fix js example test
davidism Nov 1, 2024
8aa161a
add sqlite datetime converter
davidism Nov 2, 2024
a9b99b3
update example project metadata
davidism Nov 2, 2024
c62b03b
fix example and tutorial compatibility and update metadata (#5627)
davidism Nov 2, 2024
98ae718
fix mypy finding
davidism Nov 2, 2024
6c44dd4
update helpers.send_from_directory docstring (#5599)
CheeseCake87 Nov 6, 2024
2c31603
update env file precedence
davidism Nov 7, 2024
7522c4b
update env file precedence (#5630)
davidism Nov 7, 2024
e13373f
enable secret key rotation
davidism Nov 8, 2024
a20bcff
enable secret key rotation (#5632)
davidism Nov 8, 2024
470e2b8
update min blinker version
davidism Nov 8, 2024
07c7d57
update min blinker version (#5633)
davidism Nov 8, 2024
4995a77
fix subdomain_matching=False behavior
davidism Nov 11, 2024
10bdf61
setting `SERVER_NAME` does not restrict routing for both `subdomain_m…
davidism Nov 12, 2024
4f7156f
configure and check trusted_hosts
davidism Nov 13, 2024
7b21d43
configure and check `request.trusted_hosts` (#5637)
davidism Nov 13, 2024
f49dbfd
use generic bases for session
davidism Nov 13, 2024
2eab96a
use generic bases for session (#5638)
davidism Nov 13, 2024
22c48a7
Merge remote-tracking branch 'origin/stable'
davidism Nov 13, 2024
6748a09
update dev dependencies
davidism Nov 13, 2024
70602a1
remove test pypi
davidism Nov 13, 2024
ab81496
release version 3.1.0
davidism Nov 13, 2024
bc09840
release version 3.1.0 (#5640)
davidism Nov 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/pre-commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: 3.x
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
- uses: pre-commit-ci/lite-action@9d882e7a565f7008d4faf128f27d1cb6503d4ebf # v1.0.2
- uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0
if: ${{ !cancelled() }}
6 changes: 1 addition & 5 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,6 @@ jobs:
id-token: write
steps:
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
- uses: pypa/gh-action-pypi-publish@f7600683efdcb7656dec5b29656edb7bc586e597 # v1.10.3
with:
repository-url: https://test.pypi.org/legacy/
packages-dir: artifact/
- uses: pypa/gh-action-pypi-publish@f7600683efdcb7656dec5b29656edb7bc586e597 # v1.10.3
- uses: pypa/gh-action-pypi-publish@15c56dba361d8335944d31a2ecd17d700fc7bcbc # v1.12.2
with:
packages-dir: artifact/
1 change: 0 additions & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ jobs:
- {python: '3.11'}
- {python: '3.10'}
- {python: '3.9'}
- {python: '3.8'}
- {name: PyPy, python: 'pypy-3.10', tox: pypy310}
- {name: Minimum Versions, python: '3.12', tox: py-min}
- {name: Development Versions, python: '3.9', tox: py-dev}
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.1
rev: v0.7.3
hooks:
- id: ruff
- id: ruff-format
Expand Down
22 changes: 21 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
Version 3.1.0
-------------

Unreleased
Released 2024-11-13

- Drop support for Python 3.8. :pr:`5623`
- Update minimum dependency versions to latest feature releases.
Werkzeug >= 3.1, ItsDangerous >= 2.2, Blinker >= 1.9. :pr:`5624,5633`
- Provide a configuration option to control automatic option
responses. :pr:`5496`
- ``Flask.open_resource``/``open_instance_resource`` and
``Blueprint.open_resource`` take an ``encoding`` parameter to use when
opening in text mode. It defaults to ``utf-8``. :issue:`5504`
- ``Request.max_content_length`` can be customized per-request instead of only
through the ``MAX_CONTENT_LENGTH`` config. Added
``MAX_FORM_MEMORY_SIZE`` and ``MAX_FORM_PARTS`` config. Added documentation
about resource limits to the security page. :issue:`5625`
- Add support for the ``Partitioned`` cookie attribute (CHIPS), with the
``SESSION_COOKIE_PARTITIONED`` config. :issue:`5472`
- ``-e path`` takes precedence over default ``.env`` and ``.flaskenv`` files.
``load_dotenv`` loads default files in addition to a path unless
``load_defaults=False`` is passed. :issue:`5628`
- Support key rotation with the ``SECRET_KEY_FALLBACKS`` config, a list of old
secret keys that can still be used for unsigning. Extensions will need to
add support. :issue:`5621`
- Fix how setting ``host_matching=True`` or ``subdomain_matching=False``
interacts with ``SERVER_NAME``. Setting ``SERVER_NAME`` no longer restricts
requests to only that domain. :issue:`5553`
- ``Request.trusted_hosts`` is checked during routing, and can be set through
the ``TRUSTED_HOSTS`` config. :issue:`5636`


Version 3.0.3
Expand Down
6 changes: 0 additions & 6 deletions docs/async-await.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ method in views that inherit from the :class:`flask.views.View` class, as
well as all the HTTP method handlers in views that inherit from the
:class:`flask.views.MethodView` class.

.. admonition:: Using ``async`` on Windows on Python 3.8

Python 3.8 has a bug related to asyncio on Windows. If you encounter
something like ``ValueError: set_wakeup_fd only works in main thread``,
please upgrade to Python 3.9.

.. admonition:: Using ``async`` with greenlet

When using gevent or eventlet to serve an application or patch the
Expand Down
113 changes: 106 additions & 7 deletions docs/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,22 @@ The following configuration values are used internally by Flask:

Default: ``None``

.. py:data:: SECRET_KEY_FALLBACKS

A list of old secret keys that can still be used for unsigning, most recent
first. This allows a project to implement key rotation without invalidating
active sessions or other recently-signed secrets.

Keys should be removed after an appropriate period of time, as checking each
additional key adds some overhead.

Flask's built-in secure cookie session supports this. Extensions that use
:data:`SECRET_KEY` may not support this yet.

Default: ``None``

.. versionadded:: 3.1

.. py:data:: SESSION_COOKIE_NAME

The name of the session cookie. Can be changed in case you already have a
Expand Down Expand Up @@ -173,6 +189,23 @@ The following configuration values are used internally by Flask:

Default: ``False``

.. py:data:: SESSION_COOKIE_PARTITIONED

Browsers will send cookies based on the top-level document's domain, rather
than only the domain of the document setting the cookie. This prevents third
party cookies set in iframes from "leaking" between separate sites.

Browsers are beginning to disallow non-partitioned third party cookies, so
you need to mark your cookies partitioned if you expect them to work in such
embedded situations.

Enabling this implicitly enables :data:`SESSION_COOKIE_SECURE` as well, as
it is only valid when served over HTTPS.

Default: ``False``

.. versionadded:: 3.1

.. py:data:: SESSION_COOKIE_SAMESITE

Restrict how cookies are sent with requests from external sites. Can
Expand Down Expand Up @@ -225,16 +258,40 @@ The following configuration values are used internally by Flask:

Default: ``None``

.. py:data:: TRUSTED_HOSTS

Validate :attr:`.Request.host` and other attributes that use it against
these trusted values. Raise a :exc:`~werkzeug.exceptions.SecurityError` if
the host is invalid, which results in a 400 error. If it is ``None``, all
hosts are valid. Each value is either an exact match, or can start with
a dot ``.`` to match any subdomain.

Validation is done during routing against this value. ``before_request`` and
``after_request`` callbacks will still be called.

Default: ``None``

.. versionadded:: 3.1

.. py:data:: SERVER_NAME

Inform the application what host and port it is bound to. Required
for subdomain route matching support.
Inform the application what host and port it is bound to.

Must be set if ``subdomain_matching`` is enabled, to be able to extract the
subdomain from the request.

If set, ``url_for`` can generate external URLs with only an application
context instead of a request context.
Must be set for ``url_for`` to generate external URLs outside of a
request context.

Default: ``None``

.. versionchanged:: 3.1
Does not restrict requests to only this domain, for both
``subdomain_matching`` and ``host_matching``.

.. versionchanged:: 1.0
Does not implicitly enable ``subdomain_matching``.

.. versionchanged:: 2.3
Does not affect ``SESSION_COOKIE_DOMAIN``.

Expand All @@ -259,12 +316,54 @@ The following configuration values are used internally by Flask:

.. py:data:: MAX_CONTENT_LENGTH

Don't read more than this many bytes from the incoming request data. If not
set and the request does not specify a ``CONTENT_LENGTH``, no data will be
read for security.
The maximum number of bytes that will be read during this request. If
this limit is exceeded, a 413 :exc:`~werkzeug.exceptions.RequestEntityTooLarge`
error is raised. If it is set to ``None``, no limit is enforced at the
Flask application level. However, if it is ``None`` and the request has no
``Content-Length`` header and the WSGI server does not indicate that it
terminates the stream, then no data is read to avoid an infinite stream.

Each request defaults to this config. It can be set on a specific
:attr:`.Request.max_content_length` to apply the limit to that specific
view. This should be set appropriately based on an application's or view's
specific needs.

Default: ``None``

.. versionadded:: 0.6

.. py:data:: MAX_FORM_MEMORY_SIZE

The maximum size in bytes any non-file form field may be in a
``multipart/form-data`` body. If this limit is exceeded, a 413
:exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it is
set to ``None``, no limit is enforced at the Flask application level.

Each request defaults to this config. It can be set on a specific
:attr:`.Request.max_form_memory_parts` to apply the limit to that specific
view. This should be set appropriately based on an application's or view's
specific needs.

Default: ``500_000``

.. versionadded:: 3.1

.. py:data:: MAX_FORM_PARTS

The maximum number of fields that may be present in a
``multipart/form-data`` body. If this limit is exceeded, a 413
:exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it
is set to ``None``, no limit is enforced at the Flask application level.

Each request defaults to this config. It can be set on a specific
:attr:`.Request.max_form_parts` to apply the limit to that specific view.
This should be set appropriately based on an application's or view's
specific needs.

Default: ``1_000``

.. versionadded:: 3.1

.. py:data:: TEMPLATES_AUTO_RELOAD

Reload templates when they are changed. If not set, it will be enabled in
Expand Down
3 changes: 2 additions & 1 deletion docs/extensiondev.rst
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,8 @@ ecosystem remain consistent and compatible.
indicate minimum compatibility support. For example,
``sqlalchemy>=1.4``.
9. Indicate the versions of Python supported using ``python_requires=">=version"``.
Flask itself supports Python >=3.8 as of April 2023, but this will update over time.
Flask itself supports Python >=3.9 as of October 2024, and this will update
over time.

.. _PyPI: https://pypi.org/search/?c=Framework+%3A%3A+Flask
.. _Discord Chat: https://discord.gg/pallets
Expand Down
2 changes: 1 addition & 1 deletion docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Installation
Python Version
--------------

We recommend using the latest version of Python. Flask supports Python 3.8 and newer.
We recommend using the latest version of Python. Flask supports Python 3.9 and newer.


Dependencies
Expand Down
10 changes: 10 additions & 0 deletions docs/tutorial/database.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ response is sent.
:caption: ``flaskr/db.py``

import sqlite3
from datetime import datetime

import click
from flask import current_app, g
Expand Down Expand Up @@ -132,6 +133,11 @@ Add the Python functions that will run these SQL commands to the
init_db()
click.echo('Initialized the database.')


sqlite3.register_converter(
"timestamp", lambda v: datetime.fromisoformat(v.decode())
)

:meth:`open_resource() <Flask.open_resource>` opens a file relative to
the ``flaskr`` package, which is useful since you won't necessarily know
where that location is when deploying the application later. ``get_db``
Expand All @@ -142,6 +148,10 @@ read from the file.
that calls the ``init_db`` function and shows a success message to the
user. You can read :doc:`/cli` to learn more about writing commands.

The call to :func:`sqlite3.register_converter` tells Python how to
interpret timestamp values in the database. We convert the value to a
:class:`datetime.datetime`.


Register with the Application
-----------------------------
Expand Down
40 changes: 37 additions & 3 deletions docs/web-security.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,43 @@
Security Considerations
=======================

Web applications usually face all kinds of security problems and it's very
hard to get everything right. Flask tries to solve a few of these things
for you, but there are a couple more you have to take care of yourself.
Web applications face many types of potential security problems, and it can be
hard to get everything right, or even to know what "right" is in general. Flask
tries to solve a few of these things by default, but there are other parts you
may have to take care of yourself. Many of these solutions are tradeoffs, and
will depend on each application's specific needs and threat model. Many hosting
platforms may take care of certain types of problems without the need for the
Flask application to handle them.

Resource Use
------------

A common category of attacks is "Denial of Service" (DoS or DDoS). This is a
very broad category, and different variants target different layers in a
deployed application. In general, something is done to increase how much
processing time or memory is used to handle each request, to the point where
there are not enough resources to handle legitimate requests.

Flask provides a few configuration options to handle resource use. They can
also be set on individual requests to customize only that request. The
documentation for each goes into more detail.

- :data:`MAX_CONTENT_LENGTH` or :attr:`.Request.max_content_length` controls
how much data will be read from a request. It is not set by default,
although it will still block truly unlimited streams unless the WSGI server
indicates support.
- :data:`MAX_FORM_MEMORY_SIZE` or :attr:`.Request.max_form_memory_size`
controls how large any non-file ``multipart/form-data`` field can be. It is
set to 500kB by default.
- :data:`MAX_FORM_PARTS` or :attr:`.Request.max_form_parts` controls how many
``multipart/form-data`` fields can be parsed. It is set to 1000 by default.
Combined with the default `max_form_memory_size`, this means that a form
will occupy at most 500MB of memory.

Regardless of these settings, you should also review what settings are available
from your operating system, container deployment (Docker etc), WSGI server, HTTP
server, and hosting platform. They typically have ways to set process resource
limits, timeouts, and other checks regardless of how Flask is configured.

.. _security-xss:

Expand Down
4 changes: 2 additions & 2 deletions examples/celery/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ name = "flask-example-celery"
version = "1.0.0"
description = "Example Flask application with Celery background tasks."
readme = "README.md"
requires-python = ">=3.8"
dependencies = ["flask>=2.2.2", "celery[redis]>=5.2.7"]
classifiers = ["Private :: Do Not Upload"]
dependencies = ["flask", "celery[redis]"]

[build-system]
requires = ["flit_core<4"]
Expand Down
File renamed without changes.
3 changes: 2 additions & 1 deletion examples/javascript/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ name = "js_example"
version = "1.1.0"
description = "Demonstrates making AJAX requests to Flask."
readme = "README.rst"
license = {file = "LICENSE.rst"}
license = {file = "LICENSE.txt"}
maintainers = [{name = "Pallets", email = "[email protected]"}]
classifiers = ["Private :: Do Not Upload"]
dependencies = ["flask"]

[project.urls]
Expand Down
2 changes: 1 addition & 1 deletion examples/javascript/tests/test_js_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@pytest.mark.parametrize(
("path", "template_name"),
(
("/", "xhr.html"),
("/", "fetch.html"),
("/plain", "xhr.html"),
("/fetch", "fetch.html"),
("/jquery", "jquery.html"),
Expand Down
File renamed without changes.
4 changes: 4 additions & 0 deletions examples/tutorial/flaskr/db.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import sqlite3
from datetime import datetime

import click
from flask import current_app
Expand Down Expand Up @@ -44,6 +45,9 @@ def init_db_command():
click.echo("Initialized the database.")


sqlite3.register_converter("timestamp", lambda v: datetime.fromisoformat(v.decode()))


def init_app(app):
"""Register database functions with the Flask app. This is called by
the application factory.
Expand Down
3 changes: 2 additions & 1 deletion examples/tutorial/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ name = "flaskr"
version = "1.0.0"
description = "The basic blog app built in the Flask tutorial."
readme = "README.rst"
license = {text = "BSD-3-Clause"}
license = {file = "LICENSE.txt"}
maintainers = [{name = "Pallets", email = "[email protected]"}]
classifiers = ["Private :: Do Not Upload"]
dependencies = [
"flask",
]
Expand Down
Loading