Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-Flask-Login for openSUSE:Factory checked in at 2022-06-05 21:28:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Flask-Login (Old) and /work/SRC/openSUSE:Factory/.python-Flask-Login.new.1548 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Flask-Login" Sun Jun 5 21:28:28 2022 rev:5 rq:980840 version:0.6.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-Flask-Login/python-Flask-Login.changes 2022-04-10 00:42:07.780963452 +0200 +++ /work/SRC/openSUSE:Factory/.python-Flask-Login.new.1548/python-Flask-Login.changes 2022-06-05 21:28:33.397048483 +0200 @@ -1,0 +2,12 @@ +Sun Jun 5 04:37:42 UTC 2022 - Arun Persaud <[email protected]> + +- update to version 0.6.1: + * Only preserve subdomain or host view args in unauthorized redirect + #663 + * The new utility function login_remembered returns True if the + current login is remembered across sessions. #654 + * Fix side effect potentially executing view twice for same + request. #666 + * Clarify usage of FlaskLoginClient test client in docs. #668 + +------------------------------------------------------------------- Old: ---- Flask-Login-0.6.0.tar.gz New: ---- Flask-Login-0.6.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Flask-Login.spec ++++++ --- /var/tmp/diff_new_pack.HXgLKV/_old 2022-06-05 21:28:33.829049064 +0200 +++ /var/tmp/diff_new_pack.HXgLKV/_new 2022-06-05 21:28:33.833049069 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %bcond_without test Name: python-Flask-Login -Version: 0.6.0 +Version: 0.6.1 Release: 0 Summary: User session management for Flask License: MIT ++++++ Flask-Login-0.6.0.tar.gz -> Flask-Login-0.6.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Login-0.6.0/CHANGES.md new/Flask-Login-0.6.1/CHANGES.md --- old/Flask-Login-0.6.0/CHANGES.md 2022-03-30 17:35:23.000000000 +0200 +++ new/Flask-Login-0.6.1/CHANGES.md 2022-05-02 06:10:53.000000000 +0200 @@ -1,6 +1,17 @@ Flask-Login Changelog ===================== +Version 0.6.1 +------------- + +Released on May 1st, 2022 + +- Only preserve subdomain or host view args in unauthorized redirect #663 +- The new utility function `login_remembered` returns `True` if the current + login is remembered across sessions. #654 +- Fix side effect potentially executing view twice for same request. #666 +- Clarify usage of FlaskLoginClient test client in docs. #668 + Version 0.6.0 ------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Login-0.6.0/PKG-INFO new/Flask-Login-0.6.1/PKG-INFO --- old/Flask-Login-0.6.0/PKG-INFO 2022-03-30 17:35:50.537025500 +0200 +++ new/Flask-Login-0.6.1/PKG-INFO 2022-05-02 06:11:16.258674100 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: Flask-Login -Version: 0.6.0 +Version: 0.6.1 Summary: User authentication and session management for Flask. Home-page: https://github.com/maxcountryman/flask-login Author: Matthew Frazier @@ -28,7 +28,7 @@ # Flask-Login  -[](https://coveralls.io/github/maxcountryman/flask-login?branch=master) +[](https://coveralls.io/github/maxcountryman/flask-login?branch=main) [](LICENSE) Flask-Login provides user session management for Flask. It handles the common @@ -165,7 +165,8 @@ return 'Unauthorized', 401 ``` -Complete documentation for Flask-Login is available on [ReadTheDocs](https://flask-login.readthedocs.io/en/latest/). +Documentation for Flask-Login is available on [ReadTheDocs](https://flask-login.readthedocs.io/en/latest/). +For complete understanding of available configuration, please refer to the [source code](https://github.com/maxcountryman/flask-login). ## Contributing diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Login-0.6.0/README.md new/Flask-Login-0.6.1/README.md --- old/Flask-Login-0.6.0/README.md 2022-03-30 17:35:23.000000000 +0200 +++ new/Flask-Login-0.6.1/README.md 2022-05-02 06:10:53.000000000 +0200 @@ -1,7 +1,7 @@ # Flask-Login  -[](https://coveralls.io/github/maxcountryman/flask-login?branch=master) +[](https://coveralls.io/github/maxcountryman/flask-login?branch=main) [](LICENSE) Flask-Login provides user session management for Flask. It handles the common @@ -138,7 +138,8 @@ return 'Unauthorized', 401 ``` -Complete documentation for Flask-Login is available on [ReadTheDocs](https://flask-login.readthedocs.io/en/latest/). +Documentation for Flask-Login is available on [ReadTheDocs](https://flask-login.readthedocs.io/en/latest/). +For complete understanding of available configuration, please refer to the [source code](https://github.com/maxcountryman/flask-login). ## Contributing diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Login-0.6.0/docs/index.rst new/Flask-Login-0.6.1/docs/index.rst --- old/Flask-Login-0.6.0/docs/index.rst 2022-03-30 17:35:23.000000000 +0200 +++ new/Flask-Login-0.6.1/docs/index.rst 2022-05-02 06:10:53.000000000 +0200 @@ -66,6 +66,9 @@ "How to generate good secret keys" section to generate your own secret key. DO NOT use the example one. +For a complete understanding of available configuration keys, please refer to +the `source code`_. + How it Works ============ You will need to provide a `~LoginManager.user_loader` callback. This callback @@ -150,7 +153,7 @@ It's that simple. You can then access the logged-in user with the `current_user` proxy, which is available in every template:: - {% if current_user.is_authenticated() %} + {% if current_user.is_authenticated %} Hi {{ current_user.name }}! {% endif %} @@ -483,8 +486,8 @@ Automated Testing ================= To make it easier for you to write automated tests, Flask-Login provides a -custom test client class that will set the user's login cookie for you. -To use this custom test client class, assign it to the +simple, custom test client class that will set the user's login cookie for you: +`~FlaskLoginClient`. To use this custom test client class, assign it to the :attr:`test_client_class <flask.Flask.test_client_class>` attribute on your application object, like this:: @@ -499,16 +502,25 @@ .. code-block:: python - def test_simple(self): + def test_request_with_logged_in_user(): user = User.query.get(1) with app.test_client(user=user) as client: - # this request has user 1 already logged in! - resp = client.get("/") + # This request has user 1 already logged in! + client.get("/") + +You may also pass ``fresh_login`` (``bool``, defaults to ``True``) to mark the +current login as fresh or non-fresh. -Note that you must use a keyword argument, not a positional argument. +Note that you must use keyword arguments, not positional arguments. E.g. ``test_client(user=user)`` will work, but ``test_client(user)`` will not. +Due to the way this custom test client class is implemented, you may have to +disable **session protection** to have your tests work properly. If session +protection is enabled, login sessions will be marked non-fresh in `basic` mode +or outright rejected in `strong` mode when performing requests with the test +client. + Localization ============ By default, the `LoginManager` uses ``flash`` to display messages when a user @@ -591,6 +603,8 @@ .. autofunction:: login_fresh +.. autofunction:: login_remembered + .. autofunction:: login_user .. autofunction:: logout_user @@ -658,6 +672,7 @@ marked non-fresh or deleted. It receives no additional arguments besides the app. +.. _source code: https://github.com/maxcountryman/flask-login/tree/main/src/flask_login .. _Flask documentation on signals: http://flask.pocoo.org/docs/signals/ .. _this Flask Snippet: https://web.archive.org/web/20120517003641/http://flask.pocoo.org/snippets/62/ .. _Flask documentation on sessions: http://flask.pocoo.org/docs/quickstart/#sessions diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Login-0.6.0/src/Flask_Login.egg-info/PKG-INFO new/Flask-Login-0.6.1/src/Flask_Login.egg-info/PKG-INFO --- old/Flask-Login-0.6.0/src/Flask_Login.egg-info/PKG-INFO 2022-03-30 17:35:49.000000000 +0200 +++ new/Flask-Login-0.6.1/src/Flask_Login.egg-info/PKG-INFO 2022-05-02 06:11:15.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: Flask-Login -Version: 0.6.0 +Version: 0.6.1 Summary: User authentication and session management for Flask. Home-page: https://github.com/maxcountryman/flask-login Author: Matthew Frazier @@ -28,7 +28,7 @@ # Flask-Login  -[](https://coveralls.io/github/maxcountryman/flask-login?branch=master) +[](https://coveralls.io/github/maxcountryman/flask-login?branch=main) [](LICENSE) Flask-Login provides user session management for Flask. It handles the common @@ -165,7 +165,8 @@ return 'Unauthorized', 401 ``` -Complete documentation for Flask-Login is available on [ReadTheDocs](https://flask-login.readthedocs.io/en/latest/). +Documentation for Flask-Login is available on [ReadTheDocs](https://flask-login.readthedocs.io/en/latest/). +For complete understanding of available configuration, please refer to the [source code](https://github.com/maxcountryman/flask-login). ## Contributing diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Login-0.6.0/src/flask_login/__about__.py new/Flask-Login-0.6.1/src/flask_login/__about__.py --- old/Flask-Login-0.6.0/src/flask_login/__about__.py 2022-03-30 17:35:23.000000000 +0200 +++ new/Flask-Login-0.6.1/src/flask_login/__about__.py 2022-05-02 06:10:53.000000000 +0200 @@ -1,7 +1,7 @@ __title__ = "Flask-Login" __description__ = "User session management for Flask" __url__ = "https://github.com/maxcountryman/flask-login" -__version_info__ = ("0", "6", "0") +__version_info__ = ("0", "6", "1") __version__ = ".".join(__version_info__) __author__ = "Matthew Frazier" __author_email__ = "[email protected]" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Login-0.6.0/src/flask_login/__init__.py new/Flask-Login-0.6.1/src/flask_login/__init__.py --- old/Flask-Login-0.6.0/src/flask_login/__init__.py 2022-03-30 17:35:23.000000000 +0200 +++ new/Flask-Login-0.6.1/src/flask_login/__init__.py 2022-05-02 06:10:53.000000000 +0200 @@ -29,6 +29,7 @@ from .utils import encode_cookie from .utils import fresh_login_required from .utils import login_fresh +from .utils import login_remembered from .utils import login_required from .utils import login_url from .utils import login_user @@ -68,6 +69,7 @@ "encode_cookie", "fresh_login_required", "login_fresh", + "login_remembered", "login_required", "login_url", "login_user", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Login-0.6.0/src/flask_login/utils.py new/Flask-Login-0.6.1/src/flask_login/utils.py --- old/Flask-Login-0.6.0/src/flask_login/utils.py 2022-03-30 17:35:23.000000000 +0200 +++ new/Flask-Login-0.6.1/src/flask_login/utils.py 2022-05-02 06:10:53.000000000 +0200 @@ -11,6 +11,7 @@ from flask import session from flask import url_for from werkzeug.local import LocalProxy +from werkzeug.routing import parse_rule from werkzeug.urls import url_decode from werkzeug.urls import url_encode @@ -94,10 +95,19 @@ if login_view.startswith(("https://", "http://", "/")): return login_view else: - if request.view_args is None: - return url_for(login_view) + try: + url_rule = request.url_rule.subdomain or request.url_rule.host + except AttributeError: + url_rule = None + if request.view_args and url_rule: + args = {} + for _, _, key in parse_rule(url_rule): + if not key or key not in request.view_args: + continue + args[key] = request.view_args[key] + return url_for(login_view, **args) else: - return url_for(login_view, **request.view_args) + return url_for(login_view) def login_url(login_view, next_url=None, next_field="next"): @@ -142,6 +152,20 @@ return session.get("_fresh", False) +def login_remembered(): + """ + This returns ``True`` if the current login is remembered across sessions. + """ + config = current_app.config + cookie_name = config.get("REMEMBER_COOKIE_NAME", COOKIE_NAME) + has_cookie = cookie_name in request.cookies and session.get("_remember") != "clear" + if has_cookie: + cookie = request.cookies[cookie_name] + user_id = decode_cookie(cookie) + return user_id is not None + return False + + def login_user(user, remember=False, duration=None, force=False, fresh=True): """ Logs a user in. You should pass the actual user object to this. If the @@ -272,11 +296,12 @@ pass elif not current_user.is_authenticated: return current_app.login_manager.unauthorized() - try: - # current_app.ensure_sync available in Flask >= 2.0 + + # flask 1.x compatibility + # current_app.ensure_sync is only available in Flask >= 2.0 + if callable(getattr(current_app, "ensure_sync", None)): return current_app.ensure_sync(func)(*args, **kwargs) - except AttributeError: # pragma: no cover - return func(*args, **kwargs) + return func(*args, **kwargs) return decorated_view diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Login-0.6.0/tests/test_login.py new/Flask-Login-0.6.1/tests/test_login.py --- old/Flask-Login-0.6.0/tests/test_login.py 2022-03-30 17:35:23.000000000 +0200 +++ new/Flask-Login-0.6.1/tests/test_login.py 2022-05-02 06:10:53.000000000 +0200 @@ -23,6 +23,7 @@ from flask_login import FlaskLoginClient from flask_login import fresh_login_required from flask_login import login_fresh +from flask_login import login_remembered from flask_login import login_required from flask_login import login_url from flask_login import login_user @@ -311,6 +312,10 @@ def is_fresh(): return str(login_fresh()) + @self.app.route("/is-remembered") + def is_remembered(): + return str(login_remembered()) + @self.app.route("/logout") def logout(): return str(logout_user()) @@ -377,6 +382,7 @@ result = login_user(notch) self.assertTrue(result) self.assertEqual(current_user.name, "Notch") + self.assertIs(login_fresh(), True) def test_login_user_not_fresh(self): with self.app.test_request_context(): @@ -670,23 +676,33 @@ def test_authentication_is_fresh(self): with self.app.test_client() as c: - c.get("/login-notch-remember") - result = c.get("/is-fresh") - self.assertEqual("True", result.data.decode("utf-8")) + c.get("/login-notch") + fresh_result = c.get("/is-fresh") + self.assertEqual("True", fresh_result.data.decode("utf-8")) + remembered_result = c.get("/is-remembered") + self.assertEqual("False", remembered_result.data.decode("utf-8")) def test_remember_me(self): with self.app.test_client() as c: c.get("/login-notch-remember") self._delete_session(c) - result = c.get("/username") - self.assertEqual("Notch", result.data.decode("utf-8")) + username_result = c.get("/username") + self.assertEqual("Notch", username_result.data.decode("utf-8")) + fresh_result = c.get("/is-fresh") + self.assertEqual("False", fresh_result.data.decode("utf-8")) + remembered_result = c.get("/is-remembered") + self.assertEqual("True", remembered_result.data.decode("utf-8")) def test_remember_me_custom_duration(self): with self.app.test_client() as c: c.get("/login-notch-remember-custom") self._delete_session(c) - result = c.get("/username") - self.assertEqual("Notch", result.data.decode("utf-8")) + username_result = c.get("/username") + self.assertEqual("Notch", username_result.data.decode("utf-8")) + fresh_result = c.get("/is-fresh") + self.assertEqual("False", fresh_result.data.decode("utf-8")) + remembered_result = c.get("/is-remembered") + self.assertEqual("True", remembered_result.data.decode("utf-8")) def test_remember_me_uses_custom_cookie_parameters(self): name = self.app.config["REMEMBER_COOKIE_NAME"] = "myname" @@ -868,6 +884,7 @@ c.get("/login-notch-remember") self._delete_session(c) self.assertEqual("False", c.get("/is-fresh").data.decode("utf-8")) + self.assertEqual("True", c.get("/is-remembered").data.decode("utf-8")) def test_login_persists_with_signle_x_forwarded_for(self): self.app.config["SESSION_PROTECTION"] = "strong" @@ -1022,8 +1039,10 @@ c.get("/login-notch-remember") self._delete_session(c) self.assertEqual("False", c.get("/is-fresh").data.decode("utf-8")) + self.assertEqual("True", c.get("/is-remembered").data.decode("utf-8")) c.get("/confirm-login") self.assertEqual("True", c.get("/is-fresh").data.decode("utf-8")) + self.assertEqual("True", c.get("/is-remembered").data.decode("utf-8")) def test_user_login_confirmed_signal_fired(self): with self.app.test_client() as c: @@ -1760,10 +1779,6 @@ self.app.config["LOGIN_DISABLED"] = False self.app.test_client_class = FlaskLoginClient - @self.app.route("/") - def index(): - return "Welcome!" - @self.app.route("/username") def username(): if current_user.is_authenticated: @@ -1807,8 +1822,45 @@ is_fresh = c.get("/is-fresh") self.assertEqual("False", is_fresh.data.decode("utf-8")) - def test_not_fresh_not_modified(self): + def test_session_protection_modes(self): + # Disabled + self.app.config["SESSION_PROTECTION"] = None + with self.app.test_client(user=notch, fresh_login=False) as c: + username = c.get("/username") + self.assertEqual("Notch", username.data.decode("utf-8")) + is_fresh = c.get("/is-fresh") + self.assertEqual("False", is_fresh.data.decode("utf-8")) + + with self.app.test_client(user=notch, fresh_login=True) as c: + username = c.get("/username") + self.assertEqual("Notch", username.data.decode("utf-8")) + is_fresh = c.get("/is-fresh") + self.assertEqual("True", is_fresh.data.decode("utf-8")) + + # Enabled with mode: basic self.app.config["SESSION_PROTECTION"] = "basic" - c = self.app.test_client(user=steve, fresh_login=False) - r = c.get("/username") - assert "Set-Cookie" not in r.headers + with self.app.test_client(user=notch, fresh_login=False) as c: + username = c.get("/username") + self.assertEqual("Notch", username.data.decode("utf-8")) + is_fresh = c.get("/is-fresh") + self.assertEqual("False", is_fresh.data.decode("utf-8")) + + with self.app.test_client(user=notch, fresh_login=True) as c: + username = c.get("/username") + self.assertEqual("Notch", username.data.decode("utf-8")) + is_fresh = c.get("/is-fresh") + self.assertEqual("False", is_fresh.data.decode("utf-8")) + + # Enabled with mode: strong + self.app.config["SESSION_PROTECTION"] = "strong" + with self.app.test_client(user=notch, fresh_login=False) as c: + username = c.get("/username") + self.assertEqual("Anonymous", username.data.decode("utf-8")) + is_fresh = c.get("/is-fresh") + self.assertEqual("False", is_fresh.data.decode("utf-8")) + + with self.app.test_client(user=notch, fresh_login=True) as c: + username = c.get("/username") + self.assertEqual("Anonymous", username.data.decode("utf-8")) + is_fresh = c.get("/is-fresh") + self.assertEqual("False", is_fresh.data.decode("utf-8"))
