Accepting request 1177931 from home:alarrosa:branches:devel:languages:python:flask

- Update to 5.4.3:
  + Fixes
    * Regression - some templates no longer getting correct config
    * CSRF not properly ignored for application forms using
      :py SECURITY_CSRF_PROTECT_MECHANISMS.
    * Improve jp translations
    * Regression - datetime_factory should still be an attribute
    * :py SECURITY_RETURN_GENERIC_RESPONSES hide email
      validation/syntax errors.
- Update to 5.4.2:
  + Fixes
    * OpenAPI spec missing.
    * Doc fixes
    * Update ES/IT translations
- Update to 5.4.0 & 5.4.1:
  + Features and improvements:
    * Work with Flask[async]. view decorators and signals support
      async handlers.
    * CI support for python 3.12
    * Work with py_webauthn 2.0 (and only 2.0+)
    * Improve (and simplify) Two-Factor setup. See below for
      backwards compatability issues and new functionality.
    * Improve oauth debugging support. Handle next propagation in a
      more general way.
    * Make AnonymousUser (Flask-Login) optional and deprecated.
    * Remove undocumented and untested looking in session for
      possible 'next' redirect location.
    * No longer rely on Flask-Login.unauthorized callback. See
      below for implications.
    * Changes to default unauthorized handler - remove use of

OBS-URL: https://build.opensuse.org/request/show/1177931
OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:flask/python-Flask-Security-Too?expand=0&rev=45
This commit is contained in:
Antonio Larrosa 2024-05-31 12:37:30 +00:00 committed by Git OBS Bridge
parent e13f1e343f
commit 1fc62f52ba
5 changed files with 84 additions and 801 deletions

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c1ed93aae536f2a3ff8abe1e13aec9d0d95fb7ff082fcc3b372df2a5213970d9
size 616595

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:62b19397e8d71a8d4cb8dc0d4409cc7a1497982549030396960aee518755e583
size 652228

View File

@ -1,3 +1,78 @@
-------------------------------------------------------------------
Fri May 31 12:12:17 UTC 2024 - Antonio Larrosa <alarrosa@suse.com>
- Update to 5.4.3:
+ Fixes
* Regression - some templates no longer getting correct config
* CSRF not properly ignored for application forms using
:py SECURITY_CSRF_PROTECT_MECHANISMS.
* Improve jp translations
* Regression - datetime_factory should still be an attribute
* :py SECURITY_RETURN_GENERIC_RESPONSES hide email
validation/syntax errors.
- Update to 5.4.2:
+ Fixes
* OpenAPI spec missing.
* Doc fixes
* Update ES/IT translations
- Update to 5.4.0 & 5.4.1:
+ Features and improvements:
* Work with Flask[async]. view decorators and signals support
async handlers.
* CI support for python 3.12
* Work with py_webauthn 2.0 (and only 2.0+)
* Improve (and simplify) Two-Factor setup. See below for
backwards compatability issues and new functionality.
* Improve oauth debugging support. Handle next propagation in a
more general way.
* Make AnonymousUser (Flask-Login) optional and deprecated.
* Remove undocumented and untested looking in session for
possible 'next' redirect location.
* No longer rely on Flask-Login.unauthorized callback. See
below for implications.
* Changes to default unauthorized handler - remove use of
referrer header (see below) and document precise behavior.
* The authentication_token format has changed - adding
per-token expiry time and future session ID. Old tokens are
still accepted.
+ Docs and Chores
* Improve method translations for unified signin and two
factor. Remove support for Flask-Babelex.
* Chore - stop setting all config as attributes.
init_app(**kwargs) can only set forms, flags, and utility
classes (see below for compatibility concerns).
* Update Spanish and Italian translations.
* Improve translations for two-factor method selection.
* Improve German translations.
* Remove deprecation of AUTO_LOGIN_AFTER_CONFIRM - it has a
reasonable use case.
* Update message extraction - note that the
CONFIRM_REGISTRATION message was changed to improve
readability.
+ Fixes
* us-signin magic link should use fs_uniquifier (not email).
* Improve open-redirect vulnerability mitigation. (see below)
* user_datastore.create_user has side effects on mutable
inputs. (NoRePercussions)
* The long deprecated _unauthorized_callback/handler has been
removed.
* Oauth re-used POST_LOGIN_VIEW which caused confusion. See
below for the new configuration and implications.
* Improve CSRF documentation and testing. Fix bug where a CSRF
failure could return an HTML page even if the request was
JSON.
* Register with JSON and authentication token failed CSRF.
* Fix 2 issues with CSRF configuration.
* It was possible that if SECURITY_EMAIL_VALIDATOR_ARGS were
set that deliverability would be checked even for login.
+ Backwards Compatibility Concerns
Please read the full changelog at
https://github.com/Flask-Middleware/flask-security/blob/master/CHANGES.rst#version-540--541
- Drop patch that's already included by upstream:
* support-python-312.patch
------------------------------------------------------------------- -------------------------------------------------------------------
Mon Feb 12 04:11:51 UTC 2024 - Steve Kowalik <steven.kowalik@suse.com> Mon Feb 12 04:11:51 UTC 2024 - Steve Kowalik <steven.kowalik@suse.com>

View File

@ -18,7 +18,7 @@
%{?sle15_python_module_pythons} %{?sle15_python_module_pythons}
Name: python-Flask-Security-Too Name: python-Flask-Security-Too
Version: 5.3.3 Version: 5.4.3
Release: 0 Release: 0
Summary: Security for Flask apps Summary: Security for Flask apps
License: MIT License: MIT
@ -27,8 +27,6 @@ Source: https://files.pythonhosted.org/packages/source/F/Flask-Security-
Patch0: no-mongodb.patch Patch0: no-mongodb.patch
# PATCH-FIX-OPENSUSE Use pyqrcodeng, we do not ship qrcode in OpenSUSE. # PATCH-FIX-OPENSUSE Use pyqrcodeng, we do not ship qrcode in OpenSUSE.
Patch1: use-pyqrcodeng.patch Patch1: use-pyqrcodeng.patch
# PATCH-FIX-UPSTREAM Based on gh#Flask-Middleware/flask-security#900
Patch2: support-python-312.patch
BuildRequires: %{python_module Authlib} BuildRequires: %{python_module Authlib}
BuildRequires: %{python_module Babel >= 2.10.0} BuildRequires: %{python_module Babel >= 2.10.0}
BuildRequires: %{python_module Flask >= 2.3.2} BuildRequires: %{python_module Flask >= 2.3.2}
@ -37,7 +35,7 @@ BuildRequires: %{python_module Flask-Login >= 0.6.2}
BuildRequires: %{python_module Flask-Mailman >= 0.3.0} BuildRequires: %{python_module Flask-Mailman >= 0.3.0}
BuildRequires: %{python_module Flask-Principal >= 0.4.0} BuildRequires: %{python_module Flask-Principal >= 0.4.0}
BuildRequires: %{python_module Flask-SQLAlchemy >= 3.0.3} BuildRequires: %{python_module Flask-SQLAlchemy >= 3.0.3}
BuildRequires: %{python_module Flask-WTF >= 1.1.1} BuildRequires: %{python_module Flask-WTF >= 1.1.2}
BuildRequires: %{python_module MarkupSafe >= 2.1.0} BuildRequires: %{python_module MarkupSafe >= 2.1.0}
BuildRequires: %{python_module PyQRCode >= 1.2} BuildRequires: %{python_module PyQRCode >= 1.2}
BuildRequires: %{python_module SQLAlchemy} BuildRequires: %{python_module SQLAlchemy}
@ -49,8 +47,8 @@ BuildRequires: %{python_module bcrypt >= 4.0.1}
BuildRequires: %{python_module bleach >= 6.0.0} BuildRequires: %{python_module bleach >= 6.0.0}
BuildRequires: %{python_module cachetools >= 3.1.0} BuildRequires: %{python_module cachetools >= 3.1.0}
BuildRequires: %{python_module cryptography >= 40.0.2} BuildRequires: %{python_module cryptography >= 40.0.2}
BuildRequires: %{python_module dateutil}
BuildRequires: %{python_module email-validator >= 2.0} BuildRequires: %{python_module email-validator >= 2.0}
BuildRequires: %{python_module freezegun}
BuildRequires: %{python_module importlib_resources >= 5.10.0} BuildRequires: %{python_module importlib_resources >= 5.10.0}
BuildRequires: %{python_module itsdangerous >= 1.1.0} BuildRequires: %{python_module itsdangerous >= 1.1.0}
BuildRequires: %{python_module passlib >= 1.7.4} BuildRequires: %{python_module passlib >= 1.7.4}
@ -61,6 +59,7 @@ BuildRequires: %{python_module pony if %python-base < 3.11}
BuildRequires: %{python_module pytest >= 6.2.5} BuildRequires: %{python_module pytest >= 6.2.5}
BuildRequires: %{python_module requests} BuildRequires: %{python_module requests}
BuildRequires: %{python_module setuptools} BuildRequires: %{python_module setuptools}
BuildRequires: %{python_module webauthn >= 2.0.0}
BuildRequires: %{python_module wheel} BuildRequires: %{python_module wheel}
BuildRequires: %{python_module zxcvbn >= 4.4.28} BuildRequires: %{python_module zxcvbn >= 4.4.28}
BuildRequires: fdupes BuildRequires: fdupes
@ -69,7 +68,7 @@ Requires: python-Flask >= 2.3.2
Requires: python-Flask-Babel >= 3.1.0 Requires: python-Flask-Babel >= 3.1.0
Requires: python-Flask-Login >= 0.6.2 Requires: python-Flask-Login >= 0.6.2
Requires: python-Flask-Principal >= 0.4.0 Requires: python-Flask-Principal >= 0.4.0
Requires: python-Flask-WTF >= 1.1.1 Requires: python-Flask-WTF >= 1.1.2
Requires: python-MarkupSafe >= 2.1.0 Requires: python-MarkupSafe >= 2.1.0
Requires: python-WTForms >= 3.0.0 Requires: python-WTForms >= 3.0.0
Requires: python-Werkzeug >= 2.3.3 Requires: python-Werkzeug >= 2.3.3
@ -80,6 +79,7 @@ Requires: python-email-validator >= 2.0
Requires: python-importlib_resources >= 5.10.0 Requires: python-importlib_resources >= 5.10.0
Requires: python-itsdangerous >= 1.1.0 Requires: python-itsdangerous >= 1.1.0
Requires: python-passlib >= 1.7.4 Requires: python-passlib >= 1.7.4
Requires: python-webauthn >= 2.0.0
Recommends: python-PyQRCode >= 1.2 Recommends: python-PyQRCode >= 1.2
Recommends: python-SQLAlchemy Recommends: python-SQLAlchemy
Recommends: python-zxcvbn >= 4.4.28 Recommends: python-zxcvbn >= 4.4.28

View File

@ -1,792 +0,0 @@
From f7733559de7c8cd8a5bd683b2c53b523b6fb639b Mon Sep 17 00:00:00 2001
From: Chris Wagner <jwag.wagner@gmail.com>
Date: Sun, 7 Jan 2024 15:38:43 -0800
Subject: [PATCH] Updates for python 3.12
- add CI support
- utcnow is deprecated - create our own so DB is still naive UTC timestamps
- remove use of dateutil (it was just used for tests)
- many places didn't use DATETIME_FACTORY - now they do
- update translations
- many copyright dates
- remove JSON compatibility code for Flask pre 2.x
---
.github/workflows/tests.yml | 12 +-
.pre-commit-config.yaml | 2 +-
CHANGES.rst | 1 +
LICENSE | 2 +-
README.rst | 2 +-
docs/conf.py | 4 +-
docs/configuration.rst | 5 +-
examples/unified_signin/server/api.py | 6 +-
flask_security/__init__.py | 7 +-
flask_security/core.py | 6 +-
flask_security/datastore.py | 30 +-
flask_security/json.py | 40 +--
flask_security/models/fsqla.py | 9 +-
flask_security/password_util.py | 2 +-
.../af_ZA/LC_MESSAGES/flask_security.po | 284 +++++++++--------
.../ca_ES/LC_MESSAGES/flask_security.po | 275 ++++++++--------
.../da_DK/LC_MESSAGES/flask_security.po | 275 ++++++++--------
.../de_DE/LC_MESSAGES/flask_security.po | 294 +++++++++---------
.../es_ES/LC_MESSAGES/flask_security.po | 292 ++++++++---------
.../eu_ES/LC_MESSAGES/flask_security.po | 281 +++++++++--------
.../translations/flask_security.pot | 267 ++++++++--------
.../fr_FR/LC_MESSAGES/flask_security.po | 282 +++++++++--------
.../hu_HU/LC_MESSAGES/flask_security.po | 285 +++++++++--------
.../hy_AM/LC_MESSAGES/flask_security.po | 289 ++++++++---------
.../is_IS/LC_MESSAGES/flask_security.po | 275 ++++++++--------
.../it_IT/LC_MESSAGES/flask_security.po | 285 +++++++++--------
.../ja_JP/LC_MESSAGES/flask_security.po | 275 ++++++++--------
.../nl_NL/LC_MESSAGES/flask_security.po | 287 +++++++++--------
.../pl_PL/LC_MESSAGES/flask_security.po | 287 +++++++++--------
.../pt_BR/LC_MESSAGES/flask_security.po | 275 ++++++++--------
.../pt_PT/LC_MESSAGES/flask_security.po | 275 ++++++++--------
.../ru_RU/LC_MESSAGES/flask_security.po | 287 +++++++++--------
.../tr_TR/LC_MESSAGES/flask_security.po | 275 ++++++++--------
.../zh_Hans_CN/LC_MESSAGES/flask_security.po | 277 +++++++++--------
flask_security/utils.py | 35 ++-
flask_security/webauthn.py | 7 +-
pyproject.toml | 4 +-
pytest.ini | 2 +
requirements/tests.txt | 5 +-
tests/conftest.py | 7 +-
tests/test_datastore.py | 16 +-
tests/test_webauthn.py | 7 +-
tests/view_scaffold.py | 17 +-
tox.ini | 6 +-
44 files changed, 3028 insertions(+), 2828 deletions(-)
Index: Flask-Security-Too-5.3.3/LICENSE
===================================================================
--- Flask-Security-Too-5.3.3.orig/LICENSE
+++ Flask-Security-Too-5.3.3/LICENSE
@@ -1,7 +1,7 @@
MIT License
Copyright (C) 2012-2021 by Matthew Wright
-Copyright (C) 2019-2021 by Chris Wagner
+Copyright (C) 2019-2024 by Chris Wagner
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
Index: Flask-Security-Too-5.3.3/docs/configuration.rst
===================================================================
--- Flask-Security-Too-5.3.3.orig/docs/configuration.rst
+++ Flask-Security-Too-5.3.3/docs/configuration.rst
@@ -578,9 +578,10 @@ Core - rarely need changing
.. py:data:: SECURITY_DATETIME_FACTORY
- Specifies the default datetime factory.
+ Specifies the default datetime factory. The default is naive-UTC which
+ corresponds to many DB's DateTime type.
- Default:``datetime.datetime.utcnow``.
+ Default:``flask_security.naive_utcnow``.
.. py:data:: SECURITY_CONFIRM_SALT
Index: Flask-Security-Too-5.3.3/examples/unified_signin/server/api.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/examples/unified_signin/server/api.py
+++ Flask-Security-Too-5.3.3/examples/unified_signin/server/api.py
@@ -1,10 +1,10 @@
"""
-Copyright 2020 by J. Christopher Wagner (jwag). All rights reserved.
+Copyright 2020-2024 by J. Christopher Wagner (jwag). All rights reserved.
:license: MIT, see LICENSE for more details.
"""
-from datetime import datetime
+from datetime import datetime, timezone
from flask import Blueprint, abort, current_app, jsonify
from flask_security import auth_required
@@ -17,7 +17,7 @@ api = Blueprint("api", __name__)
@api.route("/health", methods=["GET"])
@auth_required("session")
def health():
- return jsonify(secret="lush oranges", date=datetime.utcnow())
+ return jsonify(secret="lush oranges", date=datetime.now(timezone.utc))
@api.route("/popmail", methods=["GET"])
Index: Flask-Security-Too-5.3.3/flask_security/__init__.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/flask_security/__init__.py
+++ Flask-Security-Too-5.3.3/flask_security/__init__.py
@@ -2,11 +2,11 @@
flask_security
~~~~~~~~~~~~~~
- Flask-Security is a Flask extension that aims to add quick and simple
- security via Flask-Login, Flask-Principal, Flask-WTF, and passlib.
+ Flask-Security is a Flask extension that aims to add comprehensive security
+ to Flask applications.
:copyright: (c) 2012-2019 by Matt Wright.
- :copyright: (c) 2019-2023 by J. Christopher Wagner.
+ :copyright: (c) 2019-2024 by J. Christopher Wagner.
:license: MIT, see LICENSE for more details.
"""
@@ -111,6 +111,7 @@ from .utils import (
login_user,
logout_user,
lookup_identity,
+ naive_utcnow,
password_breached_validator,
password_complexity_validator,
password_length_validator,
Index: Flask-Security-Too-5.3.3/flask_security/core.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/flask_security/core.py
+++ Flask-Security-Too-5.3.3/flask_security/core.py
@@ -7,7 +7,7 @@
:copyright: (c) 2012 by Matt Wright.
:copyright: (c) 2017 by CERN.
:copyright: (c) 2017 by ETH Zurich, Swiss Data Science Center.
- :copyright: (c) 2019-2023 by J. Christopher Wagner (jwag).
+ :copyright: (c) 2019-2024 by J. Christopher Wagner (jwag).
:license: MIT, see LICENSE for more details.
"""
@@ -95,6 +95,7 @@ from .utils import (
get_identity_attributes,
get_message,
get_request_attr,
+ naive_utcnow,
localize_callback,
set_request_attr,
uia_email_mapper,
@@ -283,7 +284,7 @@ _default_config: t.Dict[str, t.Any] = {
"API_ENABLED_METHODS": ["session", "token"],
"HASHING_SCHEMES": ["sha256_crypt", "hex_md5"],
"DEPRECATED_HASHING_SCHEMES": ["hex_md5"],
- "DATETIME_FACTORY": datetime.utcnow,
+ "DATETIME_FACTORY": naive_utcnow,
"TOTP_SECRETS": None,
"TOTP_ISSUER": None,
"SMS_SERVICE": "Dummy",
@@ -1255,6 +1256,7 @@ class Security:
self.register_blueprint: bool
self.two_factor_plugins: TfPlugin
self.oauthglue: t.Optional[OAuthGlue] = None
+ self.datetime_factory: t.Callable[[], datetime]
self.login_manager: "flask_login.LoginManager"
self._mail_util: MailUtil
Index: Flask-Security-Too-5.3.3/flask_security/datastore.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/flask_security/datastore.py
+++ Flask-Security-Too-5.3.3/flask_security/datastore.py
@@ -5,10 +5,10 @@
This module contains an user datastore classes.
:copyright: (c) 2012 by Matt Wright.
- :copyright: (c) 2019-2023 by J. Christopher Wagner (jwag).
+ :copyright: (c) 2019-2024 by J. Christopher Wagner (jwag).
:license: MIT, see LICENSE for more details.
"""
-import datetime
+from datetime import datetime
import json
import typing as t
import uuid
@@ -817,6 +817,8 @@ class SQLAlchemyUserDatastore(SQLAlchemy
extensions: t.Optional[str] = None,
**kwargs: t.Any,
) -> None:
+ from .proxies import _security
+
if not hasattr(self, "webauthn_model") or not self.webauthn_model:
raise NotImplementedError
@@ -830,7 +832,7 @@ class SQLAlchemyUserDatastore(SQLAlchemy
backup_state=backup_state,
transports=transports,
extensions=extensions,
- lastuse_datetime=datetime.datetime.utcnow(),
+ lastuse_datetime=_security.datetime_factory(),
**kwargs,
)
user.webauthn.append(webauthn)
@@ -944,6 +946,8 @@ class MongoEngineUserDatastore(MongoEngi
extensions: t.Optional[str] = None,
**kwargs: t.Any,
) -> None:
+ from .proxies import _security
+
if not hasattr(self, "webauthn_model") or not self.webauthn_model:
raise NotImplementedError
webauthn = self.webauthn_model(
@@ -957,7 +961,7 @@ class MongoEngineUserDatastore(MongoEngi
backup_state=backup_state,
transports=transports,
extensions=extensions,
- lastuse_datetime=datetime.datetime.utcnow(),
+ lastuse_datetime=_security.datetime_factory(),
**kwargs,
)
user.webauthn.append(webauthn)
@@ -1079,6 +1083,8 @@ class PeeweeUserDatastore(PeeweeDatastor
extensions: t.Optional[str] = None,
**kwargs: t.Any,
) -> None:
+ from .proxies import _security
+
if not hasattr(self, "webauthn_model") or not self.webauthn_model:
raise NotImplementedError
webauthn = self.webauthn_model(
@@ -1092,7 +1098,7 @@ class PeeweeUserDatastore(PeeweeDatastor
backup_state=backup_state,
transports=transports,
extensions=extensions,
- lastuse_datetime=datetime.datetime.utcnow(),
+ lastuse_datetime=_security.datetime_factory(),
**kwargs,
)
self.put(webauthn) # type: ignore
@@ -1164,9 +1170,9 @@ if t.TYPE_CHECKING: # pragma: no cover
fs_uniquifier: str
fs_token_uniquifier: str
fs_webauthn_user_handle: str
- confirmed_at: t.Optional[datetime.datetime]
- last_login_at: datetime.datetime
- current_login_at: datetime.datetime
+ confirmed_at: t.Optional[datetime]
+ last_login_at: datetime
+ current_login_at: datetime
last_login_ip: t.Optional[str]
current_login_ip: t.Optional[str]
login_count: int
@@ -1176,8 +1182,8 @@ if t.TYPE_CHECKING: # pragma: no cover
mf_recovery_codes: t.Optional[t.List[str]]
us_phone_number: t.Optional[str]
us_totp_secrets: t.Optional[t.Union[str, bytes]]
- create_datetime: datetime.datetime
- update_datetime: datetime.datetime
+ create_datetime: datetime
+ update_datetime: datetime
roles: t.List["Role"]
webauthn: t.List["WebAuthn"]
@@ -1189,7 +1195,7 @@ if t.TYPE_CHECKING: # pragma: no cover
name: str
description: t.Optional[str]
permissions: t.Optional[t.List[str]]
- update_datetime: datetime.datetime
+ update_datetime: datetime
def __init__(self, **kwargs):
...
@@ -1204,7 +1210,7 @@ if t.TYPE_CHECKING: # pragma: no cover
backup_state: bool
device_type: str
extensions: t.Optional[str]
- lastuse_datetime: datetime.datetime
+ lastuse_datetime: datetime
user_id: int
usage: str
Index: Flask-Security-Too-5.3.3/flask_security/json.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/flask_security/json.py
+++ Flask-Security-Too-5.3.3/flask_security/json.py
@@ -1,32 +1,13 @@
"""
Flask-Security JSON extensions.
- :copyright: (c) 2022-2023 by J. Christopher Wagner (jwag).
+ :copyright: (c) 2022-2024 by J. Christopher Wagner (jwag).
:license: MIT, see LICENSE for more details.
Pieces of this code liberally copied from flask-mongoengine.
"""
-def _use_encoder(superclass): # pragma: no cover
- """Flask < 2.2"""
-
- class FsJsonEncoder(superclass):
- """Flask-Security JSON encoder.
- Extends Flask's JSONencoder to handle lazy-text.
- """
-
- def default(self, obj):
- from .babel import is_lazy_string
-
- if is_lazy_string(obj):
- return str(obj)
- else:
- return super().default(obj)
-
- return FsJsonEncoder
-
-
def _use_provider(superclass):
"""Flask 2.2 onwards - customize JSONProvider"""
@@ -44,19 +25,6 @@ def _use_provider(superclass):
def setup_json(app, bp=None):
# Called at init_app time.
- if hasattr(app, "json_provider_class"):
- # Flask >= 2.2
- app.json_provider_class = _use_provider(app.json_provider_class)
- app.json = app.json_provider_class(app)
- # a bit if a hack - if a package (e.g. flask-mongoengine) hasn't
- # converted yet - they might use json_encoder. This ONLY applies
- # to this specific version of Flask that happens to use _json_encoder to
- # signal if any app/extension has registered an old style encoder.
- # (app.json_encoder is always set)
- # (If they do, then Flask 2.2.x won't use json_provider at all)
- # Of course if they do this AFTER we're initialized all bets are off.
- if getattr(app, "_json_encoder", None):
- app.json_encoder = _use_encoder(app.json_encoder)
-
- elif bp: # pragma: no cover
- bp.json_encoder = _use_encoder(app.json_encoder)
+ # Flask >= 2.2
+ app.json_provider_class = _use_provider(app.json_provider_class)
+ app.json = app.json_provider_class(app)
Index: Flask-Security-Too-5.3.3/flask_security/models/fsqla.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/flask_security/models/fsqla.py
+++ Flask-Security-Too-5.3.3/flask_security/models/fsqla.py
@@ -1,5 +1,5 @@
"""
-Copyright 2019-2021 by J. Christopher Wagner (jwag). All rights reserved.
+Copyright 2019-2024 by J. Christopher Wagner (jwag). All rights reserved.
:license: MIT, see LICENSE for more details.
@@ -11,7 +11,6 @@ BE AWARE: Once any version of this is sh
a new version needs to be created.
"""
-import datetime
from typing import cast
from sqlalchemy import (
Boolean,
@@ -25,7 +24,7 @@ from sqlalchemy.ext.declarative import d
from sqlalchemy.ext.mutable import MutableList
from sqlalchemy.sql import func
-from flask_security import AsaList, RoleMixin, UserMixin
+from flask_security import AsaList, RoleMixin, UserMixin, naive_utcnow
class FsModels:
@@ -77,7 +76,7 @@ class FsRoleMixin(RoleMixin):
type_=DateTime,
nullable=False,
server_default=func.now(),
- onupdate=datetime.datetime.utcnow,
+ onupdate=naive_utcnow,
)
@@ -126,5 +125,5 @@ class FsUserMixin(UserMixin):
type_=DateTime,
nullable=False,
server_default=func.now(),
- onupdate=datetime.datetime.utcnow,
+ onupdate=naive_utcnow,
)
Index: Flask-Security-Too-5.3.3/flask_security/password_util.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/flask_security/password_util.py
+++ Flask-Security-Too-5.3.3/flask_security/password_util.py
@@ -4,7 +4,7 @@
Utility class providing methods for validating and normalizing passwords.
- :copyright: (c) 2020-2021 by J. Christopher Wagner (jwag).
+ :copyright: (c) 2020-2024 by J. Christopher Wagner (jwag).
:license: MIT, see LICENSE for more details.
"""
Index: Flask-Security-Too-5.3.3/flask_security/utils.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/flask_security/utils.py
+++ Flask-Security-Too-5.3.3/flask_security/utils.py
@@ -5,12 +5,12 @@
Flask-Security utils module
:copyright: (c) 2012-2019 by Matt Wright.
- :copyright: (c) 2019-2023 by J. Christopher Wagner (jwag).
+ :copyright: (c) 2019-2024 by J. Christopher Wagner (jwag).
:license: MIT, see LICENSE for more details.
"""
import abc
import base64
-import datetime
+from datetime import datetime, timedelta, timezone
from functools import partial
import hashlib
import hmac
@@ -104,6 +104,25 @@ else:
return response
+# From a miguel grinberg blog around dealing with 3.12.
+# Our default SQLAlchemy Datetime is naive.
+# Note that most code should call _security.datetime_factory()
+def aware_utcnow():
+ return datetime.now(timezone.utc)
+
+
+def aware_utcfromtimestamp(timestamp):
+ return datetime.fromtimestamp(timestamp, timezone.utc)
+
+
+def naive_utcnow():
+ return aware_utcnow().replace(tzinfo=None)
+
+
+def naive_utcfromtimestamp(timestamp):
+ return aware_utcfromtimestamp(timestamp).replace(tzinfo=None)
+
+
def find_csrf_field_name():
"""
We need to clear it on logout (since that isn't being done by Flask-WTF).
@@ -207,8 +226,8 @@ def logout_user() -> None:
def check_and_update_authn_fresh(
- within: datetime.timedelta,
- grace: datetime.timedelta,
+ within: timedelta,
+ grace: timedelta,
method: t.Optional[str] = None,
) -> bool:
"""Check if user authenticated within specified time and update grace period.
@@ -255,7 +274,7 @@ def check_and_update_authn_fresh(
# No session, you can't play.
return False
- now = datetime.datetime.utcnow()
+ now = naive_utcnow()
new_exp = now + grace
grace_ts = int(new_exp.timestamp())
@@ -271,7 +290,7 @@ def check_and_update_authn_fresh(
session["fs_gexp"] = grace_ts
return False
- authn_time = datetime.datetime.utcfromtimestamp(session["fs_paa"])
+ authn_time = naive_utcfromtimestamp(session["fs_paa"])
# allow for some time drift where it's possible authn_time is in the future
# but let's be cautious and not allow arbitrary future times
delta = now - authn_time
@@ -673,7 +692,7 @@ def get_within_delta(key, app=None):
"""
txt = config_value(key, app=app)
values = txt.split()
- return datetime.timedelta(**{values[1]: int(values[0])})
+ return timedelta(**{values[1]: int(values[0])})
def send_mail(subject, recipient, template, **context):
@@ -758,7 +777,7 @@ def get_token_status(token, serializer,
def check_and_get_token_status(
- token: str, serializer_name: str, within: datetime.timedelta
+ token: str, serializer_name: str, within: timedelta
) -> t.Tuple[bool, bool, t.Any]:
"""Get the status of a token and return data.
Index: Flask-Security-Too-5.3.3/flask_security/webauthn.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/flask_security/webauthn.py
+++ Flask-Security-Too-5.3.3/flask_security/webauthn.py
@@ -4,7 +4,7 @@
Flask-Security WebAuthn module
- :copyright: (c) 2021-2023 by J. Christopher Wagner (jwag).
+ :copyright: (c) 2021-2024 by J. Christopher Wagner (jwag).
:license: MIT, see LICENSE for more details.
This implements support for webauthn/FIDO2 Level 2 using the py_webauthn package.
@@ -36,7 +36,6 @@
"""
-import datetime
import json
import time
import typing as t
@@ -677,7 +676,7 @@ def webauthn_signin_response(token: str)
after_this_request(view_commit)
assert form.cred
assert form.user
- form.cred.lastuse_datetime = datetime.datetime.utcnow()
+ form.cred.lastuse_datetime = _security.datetime_factory()
form.cred.sign_count = form.authentication_verification.new_sign_count
form.cred.backup_state = getattr(
form.authentication_verification, "credential_backed_up", False
@@ -833,7 +832,7 @@ def webauthn_verify_response(token: str)
# update last use and sign count
after_this_request(view_commit)
assert form.cred
- form.cred.lastuse_datetime = datetime.datetime.utcnow()
+ form.cred.lastuse_datetime = _security.datetime_factory()
form.cred.sign_count = form.authentication_verification.new_sign_count
_datastore.put(form.cred)
Index: Flask-Security-Too-5.3.3/pyproject.toml
===================================================================
--- Flask-Security-Too-5.3.3.orig/pyproject.toml
+++ Flask-Security-Too-5.3.3/pyproject.toml
@@ -31,6 +31,7 @@ classifiers=[
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Development Status :: 5 - Production/Stable",
@@ -70,7 +71,6 @@ low = [
"babel==2.12.1",
"bcrypt==4.0.1",
"bleach==6.0.0",
- "python-dateutil==2.8.2",
"jinja2==3.1.2",
"itsdangerous==2.1.2",
"markupsafe==2.1.2",
@@ -82,6 +82,8 @@ low = [
"qrcode==7.4.2",
# authlib requires requests
"requests",
+ # passlib required setuptools
+ "setuptools",
"sqlalchemy==2.0.12",
"sqlalchemy-utils==0.41.1",
"webauthn==1.11.0",
Index: Flask-Security-Too-5.3.3/pytest.ini
===================================================================
--- Flask-Security-Too-5.3.3.orig/pytest.ini
+++ Flask-Security-Too-5.3.3/pytest.ini
@@ -20,6 +20,8 @@ filterwarnings =
ignore::DeprecationWarning:mongoengine:
ignore::DeprecationWarning:flask_login:0
ignore::DeprecationWarning:pydantic_core:0
+ # next for py 3.12
+ ignore::DeprecationWarning:pkg_resources:0
ignore::UserWarning:cbor2:0
ignore:.*passwordless feature.*:DeprecationWarning:flask_security:0
ignore::DeprecationWarning:passlib:0
Index: Flask-Security-Too-5.3.3/requirements/tests.txt
===================================================================
--- Flask-Security-Too-5.3.3.orig/requirements/tests.txt
+++ Flask-Security-Too-5.3.3/requirements/tests.txt
@@ -3,7 +3,7 @@ Babel
Flask-Login@git+https://github.com/maxcountryman/flask-login@main
Flask-Mailman
Flask-Principal
-peewee
+peewee; python_version < '3.12'
Flask-SQLAlchemy
argon2_cffi
authlib
@@ -13,7 +13,6 @@ check-manifest
coverage
cryptography
djlint
-python-dateutil
mongoengine
mongomock
msgcheck
@@ -27,6 +26,8 @@ pytest
qrcode
# authlib requires requests
requests
+# passlib requires setuptools which is deprecated
+setuptools
sqlalchemy
sqlalchemy-utils
webauthn
Index: Flask-Security-Too-5.3.3/tests/conftest.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/tests/conftest.py
+++ Flask-Security-Too-5.3.3/tests/conftest.py
@@ -5,7 +5,7 @@
Test fixtures and what not
:copyright: (c) 2017 by CERN.
- :copyright: (c) 2019-2022 by J. Christopher Wagner (jwag).
+ :copyright: (c) 2019-2024 by J. Christopher Wagner (jwag).
:license: MIT, see LICENSE for more details.
"""
@@ -37,6 +37,7 @@ from flask_security import (
auth_token_required,
http_auth_required,
get_request_attr,
+ naive_utcnow,
login_required,
roles_accepted,
roles_required,
@@ -563,7 +564,7 @@ def sqlalchemy_session_setup(request, ap
DateTime,
nullable=False,
server_default=func.now(),
- onupdate=datetime.utcnow,
+ onupdate=naive_utcnow,
)
class User(Base, UserMixin):
@@ -597,7 +598,7 @@ def sqlalchemy_session_setup(request, ap
DateTime,
nullable=False,
server_default=func.now(),
- onupdate=datetime.utcnow,
+ onupdate=naive_utcnow,
)
@declared_attr
Index: Flask-Security-Too-5.3.3/tests/test_datastore.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/tests/test_datastore.py
+++ Flask-Security-Too-5.3.3/tests/test_datastore.py
@@ -5,15 +5,21 @@
Datastore tests
:copyright: (c) 2012 by Matt Wright.
- :copyright: (c) 2019-2022 by J. Christopher Wagner (jwag).
+ :copyright: (c) 2019-2024 by J. Christopher Wagner (jwag).
:license: MIT, see LICENSE for more details.
"""
-import datetime
from pytest import raises, skip, importorskip
from tests.test_utils import init_app_with_options, get_num_queries, is_sqlalchemy
-from flask_security import RoleMixin, Security, UserMixin, LoginForm, RegisterForm
+from flask_security import (
+ RoleMixin,
+ Security,
+ UserMixin,
+ LoginForm,
+ RegisterForm,
+ naive_utcnow,
+)
from flask_security.datastore import Datastore, UserDatastore
@@ -294,7 +300,7 @@ def test_modify_permissions(app, datasto
assert perms == t1.get_permissions()
if hasattr(t1, "update_datetime"):
orig_update_time = t1.update_datetime
- assert t1.update_datetime <= datetime.datetime.utcnow()
+ assert t1.update_datetime <= naive_utcnow()
ds.add_permissions_to_role(t1, "execute")
ds.commit()
@@ -414,7 +420,7 @@ def test_uuid(app, request, tmpdir, real
username = Column(String(255), unique=True, nullable=True)
password = Column(String(255))
active = Column(Boolean())
- created_at = Column(DateTime, default=datetime.datetime.utcnow)
+ created_at = Column(DateTime, default=naive_utcnow())
confirmed_at = Column(DateTime())
roles = relationship(
"Role", secondary="roles_users", backref=backref("users", lazy="dynamic")
Index: Flask-Security-Too-5.3.3/tests/test_webauthn.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/tests/test_webauthn.py
+++ Flask-Security-Too-5.3.3/tests/test_webauthn.py
@@ -4,7 +4,7 @@
WebAuthn tests
- :copyright: (c) 2021-2023 by J. Christopher Wagner (jwag).
+ :copyright: (c) 2021-2024 by J. Christopher Wagner (jwag).
:license: MIT, see LICENSE for more details.
"""
@@ -12,7 +12,6 @@
from base64 import urlsafe_b64encode
import copy
import datetime
-from dateutil import parser
import json
import re
import typing as t
@@ -383,7 +382,7 @@ def test_basic_json(app, clients, get_me
response = clients.get("/wan-register", headers=headers)
active_creds = response.json["response"]["registered_credentials"]
assert active_creds[0]["name"] == "testr1"
- assert parser.parse(active_creds[0]["lastuse"]) == fake_dt
+ assert datetime.datetime.fromisoformat(active_creds[0]["lastuse"]) == fake_dt
# sign in - simple case use identity so we get back allowCredentials
logout(clients)
@@ -409,7 +408,7 @@ def test_basic_json(app, clients, get_me
# fetch credentials and verify lastuse was updated
response = clients.get("/wan-register", headers=headers)
active_creds = response.json["response"]["registered_credentials"]
- assert parser.parse(active_creds[0]["lastuse"]) != fake_dt
+ assert datetime.datetime.fromisoformat(active_creds[0]["lastuse"]) != fake_dt
assert active_creds[0]["transports"] == ["usb"]
assert active_creds[0]["usage"] == "first"
Index: Flask-Security-Too-5.3.3/tests/view_scaffold.py
===================================================================
--- Flask-Security-Too-5.3.3.orig/tests/view_scaffold.py
+++ Flask-Security-Too-5.3.3/tests/view_scaffold.py
@@ -1,4 +1,4 @@
-# :copyright: (c) 2019-2023 by J. Christopher Wagner (jwag).
+# :copyright: (c) 2019-2024 by J. Christopher Wagner (jwag).
# :license: MIT, see LICENSE for more details.
"""
@@ -21,7 +21,7 @@ data and a mail sender that flashes what
"""
-import datetime
+from datetime import timedelta
import os
import typing as t
@@ -46,7 +46,12 @@ from flask_security.signals import (
user_not_registered,
user_registered,
)
-from flask_security.utils import hash_password, uia_email_mapper, uia_phone_mapper
+from flask_security.utils import (
+ hash_password,
+ naive_utcnow,
+ uia_email_mapper,
+ uia_phone_mapper,
+)
def _find_bool(v):
@@ -101,8 +106,8 @@ def create_app():
app.config["SECURITY_TOTP_SECRETS"] = {
"1": "TjQ9Qa31VOrfEzuPy4VHQWPCTmRzCnFzMKLxXYiZu9B"
}
- app.config["SECURITY_FRESHNESS"] = datetime.timedelta(minutes=1)
- app.config["SECURITY_FRESHNESS_GRACE_PERIOD"] = datetime.timedelta(minutes=2)
+ app.config["SECURITY_FRESHNESS"] = timedelta(minutes=1)
+ app.config["SECURITY_FRESHNESS_GRACE_PERIOD"] = timedelta(minutes=2)
app.config["SECURITY_USERNAME_ENABLE"] = True
app.config["SECURITY_USERNAME_REQUIRED"] = True
app.config["SECURITY_PASSWORD_REQUIRED"] = True
@@ -286,7 +291,7 @@ def add_user(ds, email, password, roles)
roles = [ds.find_or_create_role(rn) for rn in roles]
ds.commit()
user = ds.create_user(
- email=email, password=pw, active=True, confirmed_at=datetime.datetime.utcnow()
+ email=email, password=pw, active=True, confirmed_at=naive_utcnow()
)
ds.commit()
for role in roles: