317 lines
12 KiB
Diff
317 lines
12 KiB
Diff
From 7d98a49bc38d0849367b348bfe37a2b689323419 Mon Sep 17 00:00:00 2001
|
|
From: Sha <wangsha@users.noreply.github.com>
|
|
Date: Mon, 2 Oct 2023 07:00:12 -0500
|
|
Subject: [PATCH] flask 3.0 compatibility (#778)
|
|
|
|
* Werkzeug 3.0 compatible
|
|
|
|
* python3.7 compatibility
|
|
|
|
* troubleshooting version compatibility
|
|
|
|
* update constrain
|
|
|
|
* package version troubleshooting
|
|
|
|
* troubleshooting package version
|
|
|
|
* troubleshoot package version
|
|
|
|
* package tuning
|
|
|
|
* troubleshoot package version
|
|
|
|
* troubleshooting package version
|
|
|
|
* troubleshoot test cases
|
|
|
|
* troubleshoot python package version
|
|
|
|
* Update tox.ini
|
|
|
|
* version troubleshoot
|
|
|
|
* version fix
|
|
|
|
* package version
|
|
|
|
* package version
|
|
|
|
* Update setup.py
|
|
|
|
* Update setup.py
|
|
|
|
* package version
|
|
|
|
* package version
|
|
|
|
* package version
|
|
|
|
* Update setup.cfg
|
|
|
|
* version fix
|
|
|
|
* package version
|
|
|
|
* package version
|
|
|
|
* package version
|
|
|
|
* package version
|
|
|
|
* deprecate python3.7
|
|
|
|
* package version
|
|
|
|
* merge conflicts
|
|
|
|
* pylint fix
|
|
---
|
|
.github/workflows/tests.yaml | 4 +-
|
|
requirements/ci-release.txt | 83 +++++++++------------
|
|
requirements/ci-tests.in | 5 +-
|
|
requirements/ci-tests.txt | 61 +++++++++-------
|
|
requirements/dev.txt | 138 ++++++-----------------------------
|
|
requirements/docs.txt | 50 +++++++------
|
|
requirements/style.txt | 25 +++----
|
|
requirements/tests-min.in | 8 +-
|
|
requirements/tests-min.txt | 34 ++++-----
|
|
requirements/tests.in | 6 +-
|
|
requirements/tests.txt | 28 +++----
|
|
setup.cfg | 2 +-
|
|
setup.py | 5 +-
|
|
src/flask_login/utils.py | 4 +-
|
|
tests/test_login.py | 26 ++++---
|
|
tox.ini | 2 +-
|
|
16 files changed, 198 insertions(+), 283 deletions(-)
|
|
|
|
diff --git a/src/flask_login/utils.py b/src/flask_login/utils.py
|
|
index 45a7e279..0fde23f4 100644
|
|
--- a/src/flask_login/utils.py
|
|
+++ b/src/flask_login/utils.py
|
|
@@ -1,10 +1,10 @@
|
|
import hmac
|
|
from functools import wraps
|
|
from hashlib import sha512
|
|
-from urllib.parse import urlparse
|
|
-from urllib.parse import urlunparse
|
|
from urllib.parse import parse_qs
|
|
from urllib.parse import urlencode
|
|
+from urllib.parse import urlparse
|
|
+from urllib.parse import urlunparse
|
|
|
|
from flask import current_app
|
|
from flask import g
|
|
diff --git a/tests/test_login.py b/tests/test_login.py
|
|
--- a/tests/test_login.py
|
|
+++ b/tests/test_login.py
|
|
@@ -328,7 +328,7 @@
|
|
def empty_session():
|
|
return f"modified={session.modified}"
|
|
|
|
- # This will help us with the possibility of typoes in the tests. Now
|
|
+ # This will help us with the possibility of typos in the tests. Now
|
|
# we shouldn't have to check each response to help us set up state
|
|
# (such as login pages) to make sure it worked: we will always
|
|
# get an exception raised (rather than return a 404 response)
|
|
@@ -669,24 +669,17 @@
|
|
name = self.app.config["REMEMBER_COOKIE_NAME"] = "myname"
|
|
duration = self.app.config["REMEMBER_COOKIE_DURATION"] = timedelta(days=2)
|
|
path = self.app.config["REMEMBER_COOKIE_PATH"] = "/mypath"
|
|
- domain = self.app.config["REMEMBER_COOKIE_DOMAIN"] = ".localhost.local"
|
|
+ domain = self.app.config["REMEMBER_COOKIE_DOMAIN"] = "localhost.local"
|
|
|
|
with self.app.test_client() as c:
|
|
c.get("/login-notch-remember")
|
|
|
|
- # TODO: Is there a better way to test this?
|
|
- self.assertIn(
|
|
- domain,
|
|
- c.cookie_jar._cookies,
|
|
- "Custom domain not found as cookie domain",
|
|
+ cookie = c.get_cookie(key=name, domain=domain, path=path)
|
|
+ self.assertIsNotNone(
|
|
+ cookie, "Custom domain, path and name not found in cookies"
|
|
)
|
|
- domain_cookie = c.cookie_jar._cookies[domain]
|
|
- self.assertIn(path, domain_cookie, "Custom path not found as cookie path")
|
|
- path_cookie = domain_cookie[path]
|
|
- self.assertIn(name, path_cookie, "Custom name not found as cookie name")
|
|
- cookie = path_cookie[name]
|
|
|
|
- expiration_date = datetime.utcfromtimestamp(cookie.expires)
|
|
+ expiration_date = datetime.utcfromtimestamp(cookie.expires.timestamp())
|
|
expected_date = datetime.utcnow() + duration
|
|
difference = expected_date - expiration_date
|
|
|
|
@@ -702,24 +695,17 @@
|
|
self.app.config["REMEMBER_COOKIE_DURATION"] = 172800
|
|
duration = timedelta(hours=7)
|
|
path = self.app.config["REMEMBER_COOKIE_PATH"] = "/mypath"
|
|
- domain = self.app.config["REMEMBER_COOKIE_DOMAIN"] = ".localhost.local"
|
|
+ domain = self.app.config["REMEMBER_COOKIE_DOMAIN"] = "localhost.local"
|
|
|
|
with self.app.test_client() as c:
|
|
c.get("/login-notch-remember-custom")
|
|
|
|
- # TODO: Is there a better way to test this?
|
|
- self.assertIn(
|
|
- domain,
|
|
- c.cookie_jar._cookies,
|
|
- "Custom domain not found as cookie domain",
|
|
+ cookie = c.get_cookie(key=name, domain=domain, path=path)
|
|
+ self.assertIsNotNone(
|
|
+ cookie, "Custom domain, path and name not found in cookies"
|
|
)
|
|
- domain_cookie = c.cookie_jar._cookies[domain]
|
|
- self.assertIn(path, domain_cookie, "Custom path not found as cookie path")
|
|
- path_cookie = domain_cookie[path]
|
|
- self.assertIn(name, path_cookie, "Custom name not found as cookie name")
|
|
- cookie = path_cookie[name]
|
|
|
|
- expiration_date = datetime.utcfromtimestamp(cookie.expires)
|
|
+ expiration_date = datetime.utcfromtimestamp(cookie.expires.timestamp())
|
|
expected_date = datetime.utcnow() + duration
|
|
difference = expected_date - expiration_date
|
|
|
|
@@ -734,15 +720,15 @@
|
|
self.app.config["REMEMBER_COOKIE_DURATION"] = 172800
|
|
duration = timedelta(seconds=172800)
|
|
name = self.app.config["REMEMBER_COOKIE_NAME"] = "myname"
|
|
- domain = self.app.config["REMEMBER_COOKIE_DOMAIN"] = ".localhost.local"
|
|
+ domain = self.app.config["REMEMBER_COOKIE_DOMAIN"] = "localhost.local"
|
|
|
|
with self.app.test_client() as c:
|
|
result = c.get("/login-notch-remember")
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
- cookie = c.cookie_jar._cookies[domain]["/"][name]
|
|
+ cookie = c.get_cookie(key=name, domain=domain, path="/")
|
|
|
|
- expiration_date = datetime.utcfromtimestamp(cookie.expires)
|
|
+ expiration_date = datetime.utcfromtimestamp(cookie.expires.timestamp())
|
|
expected_date = datetime.utcnow() + duration
|
|
difference = expected_date - expiration_date
|
|
|
|
@@ -794,25 +780,22 @@
|
|
self.assertIn(expected_exception_message, str(cm.exception))
|
|
|
|
def test_remember_me_refresh_every_request(self):
|
|
- domain = self.app.config["REMEMBER_COOKIE_DOMAIN"] = ".localhost.local"
|
|
+ domain = self.app.config["REMEMBER_COOKIE_DOMAIN"] = "localhost.local"
|
|
path = self.app.config["REMEMBER_COOKIE_PATH"] = "/"
|
|
|
|
# No refresh
|
|
self.app.config["REMEMBER_COOKIE_REFRESH_EACH_REQUEST"] = False
|
|
with self.app.test_client() as c:
|
|
c.get("/login-notch-remember")
|
|
- self.assertIn("remember", c.cookie_jar._cookies[domain][path])
|
|
- expiration_date_1 = datetime.utcfromtimestamp(
|
|
- c.cookie_jar._cookies[domain][path]["remember"].expires
|
|
- )
|
|
-
|
|
- self._delete_session(c)
|
|
+ cookie = c.get_cookie(key="remember", domain=domain, path=path)
|
|
+ self.assertIsNotNone(cookie)
|
|
+ expiration_date_1 = datetime.utcfromtimestamp(cookie.expires.timestamp())
|
|
|
|
+ # self._delete_session(c)
|
|
c.get("/username")
|
|
- self.assertIn("remember", c.cookie_jar._cookies[domain][path])
|
|
- expiration_date_2 = datetime.utcfromtimestamp(
|
|
- c.cookie_jar._cookies[domain][path]["remember"].expires
|
|
- )
|
|
+ cookie = c.get_cookie(key="remember", domain=domain, path=path)
|
|
+ self.assertIsNotNone(cookie)
|
|
+ expiration_date_2 = datetime.utcfromtimestamp(cookie.expires.timestamp())
|
|
self.assertEqual(expiration_date_1, expiration_date_2)
|
|
|
|
# With refresh (mock datetime's `utcnow`)
|
|
@@ -820,22 +803,24 @@
|
|
self.app.config["REMEMBER_COOKIE_REFRESH_EACH_REQUEST"] = True
|
|
now = datetime.utcnow()
|
|
mock_dt.utcnow = Mock(return_value=now)
|
|
-
|
|
+ mock_utcnow1 = mock_dt.utcnow
|
|
with self.app.test_client() as c:
|
|
c.get("/login-notch-remember")
|
|
- self.assertIn("remember", c.cookie_jar._cookies[domain][path])
|
|
+ cookie = c.get_cookie(key="remember", domain=domain, path=path)
|
|
expiration_date_1 = datetime.utcfromtimestamp(
|
|
- c.cookie_jar._cookies[domain][path]["remember"].expires
|
|
+ cookie.expires.timestamp()
|
|
)
|
|
self.assertIsNotNone(expiration_date_1)
|
|
|
|
- self._delete_session(c)
|
|
+ # self._delete_session(c)
|
|
|
|
mock_dt.utcnow = Mock(return_value=now + timedelta(seconds=1))
|
|
+ mock_utcnow2 = mock_dt.utcnow
|
|
+ self.assertNotEqual(mock_utcnow1, mock_utcnow2)
|
|
c.get("/username")
|
|
- self.assertIn("remember", c.cookie_jar._cookies[domain][path])
|
|
+ cookie = c.get_cookie(key="remember", domain=domain, path=path)
|
|
expiration_date_2 = datetime.utcfromtimestamp(
|
|
- c.cookie_jar._cookies[domain][path]["remember"].expires
|
|
+ cookie.expires.timestamp()
|
|
)
|
|
self.assertIsNotNone(expiration_date_2)
|
|
self.assertNotEqual(expiration_date_1, expiration_date_2)
|
|
@@ -1016,7 +1001,7 @@
|
|
c.get("/login-notch-remember")
|
|
with c.session_transaction() as sess:
|
|
sess["_user_id"] = None
|
|
- c.set_cookie(domain, self.remember_cookie_name, "foo")
|
|
+ c.set_cookie(self.remember_cookie_name, "foo", domain=domain)
|
|
result = c.get("/username")
|
|
self.assertEqual("Anonymous", result.data.decode("utf-8"))
|
|
|
|
@@ -1315,7 +1300,7 @@
|
|
pass
|
|
return USERS.get(user_id)
|
|
|
|
- # This will help us with the possibility of typoes in the tests. Now
|
|
+ # This will help us with the possibility of typos in the tests. Now
|
|
# we shouldn't have to check each response to help us set up state
|
|
# (such as login pages) to make sure it worked: we will always
|
|
# get an exception raised (rather than return a 404 response)
|
|
@@ -1426,9 +1411,10 @@
|
|
result = login_url("https://auth.localhost/login", PROTECTED)
|
|
self.assertEqual(expected, result)
|
|
|
|
+ url = login_url("/login?affil=cgnu", PROTECTED)
|
|
self.assertEqual(
|
|
"/login?affil=cgnu&next=%2Fprotected",
|
|
- login_url("/login?affil=cgnu", PROTECTED),
|
|
+ url,
|
|
)
|
|
|
|
def test_login_url_generation_with_view(self):
|
|
@@ -1590,7 +1576,7 @@
|
|
def load_user(user_id):
|
|
return USERS[str(user_id)]
|
|
|
|
- # This will help us with the possibility of typoes in the tests. Now
|
|
+ # This will help us with the possibility of typos in the tests. Now
|
|
# we shouldn't have to check each response to help us set up state
|
|
# (such as login pages) to make sure it worked: we will always
|
|
# get an exception raised (rather than return a 404 response)
|
|
@@ -1646,7 +1632,7 @@
|
|
def load_user(user_id):
|
|
return USERS[str(user_id)]
|
|
|
|
- # This will help us with the possibility of typoes in the tests. Now
|
|
+ # This will help us with the possibility of typos in the tests. Now
|
|
# we shouldn't have to check each response to help us set up state
|
|
# (such as login pages) to make sure it worked: we will always
|
|
# get an exception raised (rather than return a 404 response)
|
|
@@ -1742,7 +1728,7 @@
|
|
def load_user(user_id):
|
|
return USERS[int(user_id)]
|
|
|
|
- # This will help us with the possibility of typoes in the tests. Now
|
|
+ # This will help us with the possibility of typos in the tests. Now
|
|
# we shouldn't have to check each response to help us set up state
|
|
# (such as login pages) to make sure it worked: we will always
|
|
# get an exception raised (rather than return a 404 response)
|