Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-Flask-Paranoid for 
openSUSE:Factory checked in at 2022-05-24 20:31:33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-Flask-Paranoid (Old)
 and      /work/SRC/openSUSE:Factory/.python-Flask-Paranoid.new.2254 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-Flask-Paranoid"

Tue May 24 20:31:33 2022 rev:5 rq:978800 version:0.3.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-Flask-Paranoid/python-Flask-Paranoid.changes  
    2021-09-14 21:15:20.240460843 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-Flask-Paranoid.new.2254/python-Flask-Paranoid.changes
    2022-05-24 20:32:03.646956561 +0200
@@ -1,0 +2,9 @@
+Tue May 24 02:58:33 UTC 2022 - Fusion Future <qydwhotm...@gmail.com>
+
+- Update to 0.3.0
+  * Project restructure and test fixes
+- Bump minimum required python version to 3.7
+- Fix compatibility with old Flask versions
+  * fix-ParanoidTests-fail.patch
+
+-------------------------------------------------------------------

Old:
----
  v0.2.tar.gz

New:
----
  v0.3.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-Flask-Paranoid.spec ++++++
--- /var/tmp/diff_new_pack.w3uVCa/_old  2022-05-24 20:32:04.258957106 +0200
+++ /var/tmp/diff_new_pack.w3uVCa/_new  2022-05-24 20:32:04.262957110 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-Flask-Paranoid
 #
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,9 +16,12 @@
 #
 
 
+%define skip_python2 1
+%define skip_python36 1
+
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-Flask-Paranoid
-Version:        0.2.0
+Version:        0.3.0
 Release:        0
 License:        MIT
 Summary:        Flask user session protection
@@ -26,7 +29,7 @@
 Group:          Development/Languages/Python
 # Pypi sources don't include tests
 #Source:         
https://files.pythonhosted.org/packages/source/F/Flask-Paranoid/Flask-Paranoid-%%{version}.tar.gz
-Source:         
https://github.com/miguelgrinberg/flask-paranoid/archive/v0.2.tar.gz
+Source:         
https://github.com/miguelgrinberg/flask-paranoid/archive/refs/tags/v%{version}.tar.gz
 Source99:       
https://raw.githubusercontent.com/miguelgrinberg/flask-paranoid/master/LICENSE
 # PATCH-FIX-OPENSUSE fix-ParanoidTests-fail.patch The minus sign is removed 
from HTTP headers in newer Python releases.
 Patch0:         fix-ParanoidTests-fail.patch
@@ -52,10 +55,8 @@
 agent when a client connects to the flask application.
 
 %prep
-%setup -q -n flask-paranoid-0.2
-%if 0%{?suse_version} > 1500
+%setup -q -n flask-paranoid-%{version}
 %patch0 -p1
-%endif
 cp %{SOURCE99} .
 
 %build
@@ -66,7 +67,11 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
+%if 0%{?suse_version} > 1500
 %pyunittest discover -v
+%else
+%python_exec setup.py test
+%endif
 
 %files %{python_files}
 %license LICENSE

++++++ fix-ParanoidTests-fail.patch ++++++
--- /var/tmp/diff_new_pack.w3uVCa/_old  2022-05-24 20:32:04.302957145 +0200
+++ /var/tmp/diff_new_pack.w3uVCa/_new  2022-05-24 20:32:04.306957149 +0200
@@ -1,12 +1,27 @@
---- a/tests/test_paranoid.py
-+++ b/tests/test_paranoid.py
-@@ -7,7 +7,7 @@ from flask_paranoid import Paranoid
+Index: flask-paranoid-0.3.0/tests/test_paranoid.py
+===================================================================
+--- flask-paranoid-0.3.0.orig/tests/test_paranoid.py
++++ flask-paranoid-0.3.0/tests/test_paranoid.py
+@@ -1,12 +1,21 @@
+ import sys
+ import unittest
+ 
++import flask
+ from flask import Flask
+ from flask_paranoid import Paranoid
+ 
  
  class ParanoidTests(unittest.TestCase):
-     def _delete_cookie(self, name):
--        return (name + '=; Expires=Thu, 01-Jan-1970 00:00:00 GMT; '
-+        return (name + '=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; '
-                 'Max-Age=0; Path=/')
+     def _delete_cookie(self, name, httponly=True):
++        flask_version = flask.__version__.split('.')
++        if int(flask_version[0]) < 2 or (int(flask_version[0]) == 2 and 
int(flask_version[1]) < 1):
++            httponly = False
++
++        if (sys.version_info.minor < 8):
++            return (name + '=; Expires=Thu, 01-Jan-1970 00:00:00 GMT; '
++                    f'Max-Age=0; {"HttpOnly; " if httponly else ""}Path=/')
++
+         return (name + '=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; '
+                 f'Max-Age=0; {"HttpOnly; " if httponly else ""}Path=/')
  
-     def test_401(self):
 

++++++ v0.2.tar.gz -> v0.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/.github/workflows/tests.yml 
new/flask-paranoid-0.3.0/.github/workflows/tests.yml
--- old/flask-paranoid-0.2/.github/workflows/tests.yml  1970-01-01 
01:00:00.000000000 +0100
+++ new/flask-paranoid-0.3.0/.github/workflows/tests.yml        2022-04-02 
18:26:49.000000000 +0200
@@ -0,0 +1,45 @@
+name: build
+on:
+  push:
+    branches:
+      - main
+  pull_request:
+    branches:
+      - main
+jobs:
+  lint:
+    name: lint
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions/setup-python@v2
+      - run: python -m pip install --upgrade pip wheel
+      - run: pip install tox tox-gh-actions
+      - run: tox -eflake8
+      - run: tox -edocs
+  tests:
+    name: tests
+    strategy:
+      matrix:
+        os: [ubuntu-latest, macos-latest, windows-latest]
+        python: ['3.7', '3.8', '3.9', '3.10', 'pypy-3.8']
+      fail-fast: false
+    runs-on: ${{ matrix.os }}
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.python }}
+      - run: python -m pip install --upgrade pip wheel
+      - run: pip install tox tox-gh-actions
+      - run: tox
+  coverage:
+    name: coverage
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions/setup-python@v2
+      - run: python -m pip install --upgrade pip wheel
+      - run: pip install tox tox-gh-actions codecov
+      - run: tox
+      - run: codecov
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/CHANGES.md 
new/flask-paranoid-0.3.0/CHANGES.md
--- old/flask-paranoid-0.2/CHANGES.md   1970-01-01 01:00:00.000000000 +0100
+++ new/flask-paranoid-0.3.0/CHANGES.md 2022-04-02 18:26:49.000000000 +0200
@@ -0,0 +1,26 @@
+# flask-paranoid change log
+
+**Release 0.3.0** - 2022-04-02
+
+- Project restructure and test fixes 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/a63fd06d56867969f971f66f1958611fc916e570))
+- Refreshed requirements for the example app 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/d11124c875df3b299ff63669a3dde7f1b3d0b45b))
+- Add change log 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/d48ff73b453178ed7deec327565b79dc619d4633))
+- Update build badges 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/d984efe7ce0682da9dfea3c682670670dc59cc6e))
+- Github actions build 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/ea84d08e5a3e8f5c76eb48829314822c6c3bcbad))
+- Add LICENSE file to source distribution 
[#4](https://github.com/miguelgrinberg/flask-paranoid/issues/4) 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/c1c77443586b80263953fa5ed1d06dace876bce7))
 (thanks **Nehal J Wani**!)
+
+**Release 0.2.0** - 2017-11-17
+
+- Update requirements.txt 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/ce48283ac4043c83df913edf24fa826945b60922))
+- Fixed documentation link 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/5a19267cb49b09024e1d3f42c9b8f0d40d1d071f))
+- documentation fixes 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/c0f78688337286a6544cebf8ea54a4985a6a8803))
+
+**Release 0.1** - 2017-07-02
+
+- readme file 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/1dd96831e4b56d019577f590c2b3792dee1e7aaf))
+- documentation 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/91dbad3d6e16b9f4b1e036669b50a706b07dc2fe))
+- more unit tests 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/e5d515728b71df4f253d536b618149131bf44a32))
+- first unit test 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/6678497c0a0b0b98b6353207d5ab7de122b9d7c8))
+- tox and travis build setup 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/5788c24f0f79f3a8fd336b00603a066e00d8c084))
+- fleshed out the extension, and added an example 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/11c4dc0dbf279d71afd477560ad734cb1f423edf))
+- initial commit 
([commit](https://github.com/miguelgrinberg/flask-paranoid/commit/7fd342a2ad2360a7ab312b5c0d2a2c5df1c2bdf1))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/MANIFEST.in 
new/flask-paranoid-0.3.0/MANIFEST.in
--- old/flask-paranoid-0.2/MANIFEST.in  1970-01-01 01:00:00.000000000 +0100
+++ new/flask-paranoid-0.3.0/MANIFEST.in        2022-04-02 18:26:49.000000000 
+0200
@@ -0,0 +1,2 @@
+include LICENSE
+exclude MANIFEST.in
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/README.md 
new/flask-paranoid-0.3.0/README.md
--- old/flask-paranoid-0.2/README.md    2017-11-17 20:44:46.000000000 +0100
+++ new/flask-paranoid-0.3.0/README.md  2022-04-02 18:26:49.000000000 +0200
@@ -1,7 +1,7 @@
 flask-paranoid
 ==============
 
-[![Build 
Status](https://travis-ci.org/miguelgrinberg/flask-paranoid.svg?branch=master)](https://travis-ci.org/miguelgrinberg/flask-paranoid)
+[![Build 
status](https://github.com/miguelgrinberg/flask-paranoid/workflows/build/badge.svg)](https://github.com/miguelgrinberg/flask-paranoid/actions)
 
[![codecov](https://codecov.io/gh/miguelgrinberg/flask-paranoid/branch/main/graph/badge.svg)](https://codecov.io/gh/miguelgrinberg/flask-paranoid)
 
 Simple user session protection.
 
@@ -37,3 +37,4 @@
 
 - [Documentation](http://pythonhosted.org/Flask-Paranoid)
 - [PyPI](https://pypi.python.org/pypi/flask-paranoid)
+- [Change 
Log](https://github.com/miguelgrinberg/flask-paranoid/blob/main/CHANGES.md)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/example/requirements.txt 
new/flask-paranoid-0.3.0/example/requirements.txt
--- old/flask-paranoid-0.2/example/requirements.txt     2017-11-17 
20:44:46.000000000 +0100
+++ new/flask-paranoid-0.3.0/example/requirements.txt   2022-04-02 
18:26:49.000000000 +0200
@@ -1,8 +1,8 @@
-click==6.7
-Flask==0.12.2
-Flask-Login==0.4.0
-Flask-Paranoid
-itsdangerous==0.24
-Jinja2==2.9.6
-MarkupSafe==1.0
-Werkzeug==0.12.2
+click==8.0.3
+Flask==2.0.2
+Flask-Login==0.5.0
+Flask_Paranoid
+itsdangerous==2.0.1
+Jinja2==3.0.3
+MarkupSafe==2.0.1
+Werkzeug==2.0.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/flask_paranoid/__init__.py 
new/flask-paranoid-0.3.0/flask_paranoid/__init__.py
--- old/flask-paranoid-0.2/flask_paranoid/__init__.py   2017-11-17 
20:44:46.000000000 +0100
+++ new/flask-paranoid-0.3.0/flask_paranoid/__init__.py 1970-01-01 
01:00:00.000000000 +0100
@@ -1 +0,0 @@
-from .paranoid import Paranoid  # noqa: F401
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/flask_paranoid/paranoid.py 
new/flask-paranoid-0.3.0/flask_paranoid/paranoid.py
--- old/flask-paranoid-0.2/flask_paranoid/paranoid.py   2017-11-17 
20:44:46.000000000 +0100
+++ new/flask-paranoid-0.3.0/flask_paranoid/paranoid.py 1970-01-01 
01:00:00.000000000 +0100
@@ -1,113 +0,0 @@
-from hashlib import sha256
-import sys
-
-from flask import session, request, make_response, url_for, current_app, \
-    redirect
-from werkzeug.exceptions import Unauthorized
-
-
-class Paranoid(object):
-    def __init__(self, app=None):
-        self.invalid_session_handler = self._default_invalid_session_handler
-        if app:
-            self.init_app(app)
-
-    def init_app(self, app):
-        @app.before_request
-        def before_request():
-            token = self.create_token()
-            existing_token = self.get_token_from_session()
-            if existing_token is None:
-                # this is a new session, so we write our id in it
-                self.write_token_to_session(token)
-            elif existing_token != token:
-                # this session is invalid, so we get rid of it
-                if callable(self.invalid_session_handler):
-                    response = make_response(self.invalid_session_handler())
-                else:
-                    if self.invalid_session_handler.startswith(
-                            ('http://', 'https://', '/')):
-                        url = self.invalid_session_handler
-                    else:
-                        url = url_for(self.invalid_session_handler)
-                    response = redirect(url)
-                self.clear_session(response)
-                return response
-
-    def on_invalid_session(self, f):
-        self.invalid_session_handler = f
-        return f
-
-    def _default_invalid_session_handler(self):
-        try:
-            raise Unauthorized()
-        except Exception as e:
-            response = current_app.handle_user_exception(e)
-        return response
-
-    @property
-    def redirect_view(self):
-        return self.invalid_session_handler
-
-    @redirect_view.setter
-    def redirect_view(self, view):
-        self.invalid_session_handler = view
-
-    def _get_remote_addr(self):
-        address = request.headers.get('X-Forwarded-For', request.remote_addr)
-        if address is None:  # pragma: no cover
-            address = 'x.x.x.x'
-        address = address.encode('utf-8').split(b',')[0].strip()
-        return address
-
-    def create_token(self):
-        """Create a session protection token for this client.
-
-        This method generates a session protection token for the cilent, which
-        consists in a hash of the user agent and the IP address. This method
-        can be overriden by subclasses to implement different token generation
-        algorithms.
-        """
-        user_agent = request.headers.get('User-Agent')
-        if user_agent is None:  # pragma: no cover
-            user_agent = 'no user agent'
-        user_agent = user_agent.encode('utf-8')
-        base = self._get_remote_addr() + b'|' + user_agent
-        h = sha256()
-        h.update(base)
-        return h.hexdigest()
-
-    def get_token_from_session(self):
-        """Return the session protection token stored from the client session.
-
-        This method retrieves the stored session protection token, or None if
-        this is a brand new session that doesn't have a token in it. This
-        default implementation finds the token in the user session. Subclasses
-        can override this method and implement other storage methods.
-        """
-        return session.get('_paranoid_token')
-
-    def write_token_to_session(self, token):
-        """Write a session protection token to the client session.
-
-        This methods writes the session protection token. This default
-        implementation writes the token to the user session. Subclasses can
-        override this method to implement other storage methods.
-        """
-        session['_paranoid_token'] = token
-
-    def clear_session(self, response):
-        """Clear the session.
-
-        This method is invoked when the session is found to be invalid.
-        Subclasses can override this method to implement a custom session
-        reset.
-        """
-        session.clear()
-
-        # if flask-login is installed, we try to clear the
-        # "remember me" cookie, just in case it is set
-        if 'flask_login' in sys.modules:
-            remember_cookie = current_app.config.get('REMEMBER_COOKIE',
-                                                     'remember_token')
-            response.set_cookie(remember_cookie, '', expires=0, max_age=0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/pyproject.toml 
new/flask-paranoid-0.3.0/pyproject.toml
--- old/flask-paranoid-0.2/pyproject.toml       1970-01-01 01:00:00.000000000 
+0100
+++ new/flask-paranoid-0.3.0/pyproject.toml     2022-04-02 18:26:49.000000000 
+0200
@@ -0,0 +1,6 @@
+[build-system]
+requires = [
+    "setuptools>=42",
+    "wheel"
+]
+build-backend = "setuptools.build_meta"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/setup.cfg 
new/flask-paranoid-0.3.0/setup.cfg
--- old/flask-paranoid-0.2/setup.cfg    1970-01-01 01:00:00.000000000 +0100
+++ new/flask-paranoid-0.3.0/setup.cfg  2022-04-02 18:26:49.000000000 +0200
@@ -0,0 +1,29 @@
+[metadata]
+name = Flask-Paranoid
+version = 0.3.0
+author = Miguel Grinberg
+author_email = miguel.grinb...@gmail.com
+description = Simple user session protection
+long_description = file: README.md
+long_description_content_type = text/markdown
+url = https://github.com/miguelgrinberg/flask-paranoid
+project_urls =
+    Bug Tracker = https://github.com/miguelgrinberg/flask-paranoid/issues
+classifiers =
+    Intended Audience :: Developers
+    Programming Language :: Python :: 3
+    License :: OSI Approved :: MIT License
+    Operating System :: OS Independent
+
+[options]
+zip_safe = False
+include_package_data = True
+package_dir =
+    = src
+packages = find:
+python_requires = >=3.6
+install_requires =
+    Flask>=0.10
+
+[options.packages.find]
+where = src
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/setup.py 
new/flask-paranoid-0.3.0/setup.py
--- old/flask-paranoid-0.2/setup.py     2017-11-17 20:44:46.000000000 +0100
+++ new/flask-paranoid-0.3.0/setup.py   2022-04-02 18:26:49.000000000 +0200
@@ -1,38 +1,3 @@
-"""
-Flask-Paranoid
---------------
+import setuptools
 
-Simple user session protection.
-"""
-from setuptools import setup
-
-
-setup(
-    name='Flask-Paranoid',
-    version='0.2.0',
-    url='http://github.com/miguelgrinberg/flask-paranoid/',
-    license='MIT',
-    author='Miguel Grinberg',
-    author_email='miguelgrinber...@gmail.com',
-    description=('Simple user session protection'),
-    long_description=__doc__,
-    packages=['flask_paranoid'],
-    zip_safe=False,
-    include_package_data=True,
-    platforms='any',
-    install_requires=[
-        'Flask>=0.10',
-    ],
-    test_suite="tests",
-    classifiers=[
-        'Environment :: Web Environment',
-        'Intended Audience :: Developers',
-        'License :: OSI Approved :: MIT License',
-        'Operating System :: OS Independent',
-        'Programming Language :: Python',
-        'Programming Language :: Python :: 2',
-        'Programming Language :: Python :: 3',
-        'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
-        'Topic :: Software Development :: Libraries :: Python Modules'
-    ]
-)
+setuptools.setup()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/src/flask_paranoid/__init__.py 
new/flask-paranoid-0.3.0/src/flask_paranoid/__init__.py
--- old/flask-paranoid-0.2/src/flask_paranoid/__init__.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/flask-paranoid-0.3.0/src/flask_paranoid/__init__.py     2022-04-02 
18:26:49.000000000 +0200
@@ -0,0 +1 @@
+from .paranoid import Paranoid  # noqa: F401
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/src/flask_paranoid/paranoid.py 
new/flask-paranoid-0.3.0/src/flask_paranoid/paranoid.py
--- old/flask-paranoid-0.2/src/flask_paranoid/paranoid.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/flask-paranoid-0.3.0/src/flask_paranoid/paranoid.py     2022-04-02 
18:26:49.000000000 +0200
@@ -0,0 +1,113 @@
+from hashlib import sha256
+import sys
+
+from flask import session, request, make_response, url_for, current_app, \
+    redirect
+from werkzeug.exceptions import Unauthorized
+
+
+class Paranoid(object):
+    def __init__(self, app=None):
+        self.invalid_session_handler = self._default_invalid_session_handler
+        if app:
+            self.init_app(app)
+
+    def init_app(self, app):
+        @app.before_request
+        def before_request():
+            token = self.create_token()
+            existing_token = self.get_token_from_session()
+            if existing_token is None:
+                # this is a new session, so we write our id in it
+                self.write_token_to_session(token)
+            elif existing_token != token:
+                # this session is invalid, so we get rid of it
+                if callable(self.invalid_session_handler):
+                    response = make_response(self.invalid_session_handler())
+                else:
+                    if self.invalid_session_handler.startswith(
+                            ('http://', 'https://', '/')):
+                        url = self.invalid_session_handler
+                    else:
+                        url = url_for(self.invalid_session_handler)
+                    response = redirect(url)
+                self.clear_session(response)
+                return response
+
+    def on_invalid_session(self, f):
+        self.invalid_session_handler = f
+        return f
+
+    def _default_invalid_session_handler(self):
+        try:
+            raise Unauthorized()
+        except Exception as e:
+            response = current_app.handle_user_exception(e)
+        return response
+
+    @property
+    def redirect_view(self):
+        return self.invalid_session_handler
+
+    @redirect_view.setter
+    def redirect_view(self, view):
+        self.invalid_session_handler = view
+
+    def _get_remote_addr(self):
+        address = request.headers.get('X-Forwarded-For', request.remote_addr)
+        if address is None:  # pragma: no cover
+            address = 'x.x.x.x'
+        address = address.encode('utf-8').split(b',')[0].strip()
+        return address
+
+    def create_token(self):
+        """Create a session protection token for this client.
+
+        This method generates a session protection token for the cilent, which
+        consists in a hash of the user agent and the IP address. This method
+        can be overriden by subclasses to implement different token generation
+        algorithms.
+        """
+        user_agent = request.headers.get('User-Agent')
+        if user_agent is None:  # pragma: no cover
+            user_agent = 'no user agent'
+        user_agent = user_agent.encode('utf-8')
+        base = self._get_remote_addr() + b'|' + user_agent
+        h = sha256()
+        h.update(base)
+        return h.hexdigest()
+
+    def get_token_from_session(self):
+        """Return the session protection token stored from the client session.
+
+        This method retrieves the stored session protection token, or None if
+        this is a brand new session that doesn't have a token in it. This
+        default implementation finds the token in the user session. Subclasses
+        can override this method and implement other storage methods.
+        """
+        return session.get('_paranoid_token')
+
+    def write_token_to_session(self, token):
+        """Write a session protection token to the client session.
+
+        This methods writes the session protection token. This default
+        implementation writes the token to the user session. Subclasses can
+        override this method to implement other storage methods.
+        """
+        session['_paranoid_token'] = token
+
+    def clear_session(self, response):
+        """Clear the session.
+
+        This method is invoked when the session is found to be invalid.
+        Subclasses can override this method to implement a custom session
+        reset.
+        """
+        session.clear()
+
+        # if flask-login is installed, we try to clear the
+        # "remember me" cookie, just in case it is set
+        if 'flask_login' in sys.modules:
+            remember_cookie = current_app.config.get('REMEMBER_COOKIE',
+                                                     'remember_token')
+            response.set_cookie(remember_cookie, '', expires=0, max_age=0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/tests/test_paranoid.py 
new/flask-paranoid-0.3.0/tests/test_paranoid.py
--- old/flask-paranoid-0.2/tests/test_paranoid.py       2017-11-17 
20:44:46.000000000 +0100
+++ new/flask-paranoid-0.3.0/tests/test_paranoid.py     2022-04-02 
18:26:49.000000000 +0200
@@ -6,9 +6,9 @@
 
 
 class ParanoidTests(unittest.TestCase):
-    def _delete_cookie(self, name):
-        return (name + '=; Expires=Thu, 01-Jan-1970 00:00:00 GMT; '
-                'Max-Age=0; Path=/')
+    def _delete_cookie(self, name, httponly=True):
+        return (name + '=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; '
+                f'Max-Age=0; {"HttpOnly; " if httponly else ""}Path=/')
 
     def test_401(self):
         app = Flask(__name__)
@@ -53,7 +53,7 @@
 
         rv = client.get('/', headers={'User-Agent': 'bar'})
         self.assertEqual(rv.status_code, 302)
-        self.assertEqual(rv.headers['Location'], 'http://localhost/foobarbaz')
+        self.assertTrue(rv.headers['Location'].endswith('/foobarbaz'))
         self.assertIn(self._delete_cookie('session'),
                       rv.headers.getlist('Set-Cookie'))
         self.assertNotIn(self._delete_cookie('remember_token'),
@@ -107,7 +107,7 @@
 
         rv = client.get('/', headers={'User-Agent': 'bar'})
         self.assertEqual(rv.status_code, 302)
-        self.assertEqual(rv.headers['Location'], 'http://localhost/redirect')
+        self.assertTrue(rv.headers['Location'].endswith('/redirect'))
         self.assertIn(self._delete_cookie('session'),
                       rv.headers.getlist('Set-Cookie'))
         self.assertNotIn(self._delete_cookie('remember_token'),
@@ -167,5 +167,5 @@
         self.assertEqual(rv.headers['Location'], 'https://foo.com/foobarbaz')
         self.assertIn(self._delete_cookie('session'),
                       rv.headers.getlist('Set-Cookie'))
-        self.assertIn(self._delete_cookie('remember_token'),
+        self.assertIn(self._delete_cookie('remember_token', httponly=False),
                       rv.headers.getlist('Set-Cookie'))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flask-paranoid-0.2/tox.ini 
new/flask-paranoid-0.3.0/tox.ini
--- old/flask-paranoid-0.2/tox.ini      2017-11-17 20:44:46.000000000 +0100
+++ new/flask-paranoid-0.3.0/tox.ini    2022-04-02 18:26:49.000000000 +0200
@@ -1,30 +1,30 @@
 [tox]
-envlist=flake8,py27,py34,py35,py36,pypy,docs
+envlist=flake8,py37,py38,py39,py310,pypy3,docs
 skip_missing_interpreters=True
 
+[gh-actions]
+python =
+    3.7: py37
+    3.8: py38
+    3.9: py39
+    3.10: py310
+    pypy-3: pypy3
+
 [testenv]
 commands=
-    coverage run --branch --include="flask_paranoid/*" setup.py test
-    coverage report --show-missing
-    coverage erase
+    pip install -e .
+    pytest -p no:logging --cov=flask_paranoid --cov-branch 
--cov-report=term-missing
 deps=
-    coverage
-basepython =
-    py27: python2.7
-    py34: python3.4
-    py35: python3.5
-    py36: python3.6
-    pypy: pypy
+    pytest
+    pytest-cov
 
 [testenv:flake8]
-basepython=python3
+commands=
+    flake8 --exclude=".*" --ignore=E402 src/flask_paranoid tests
 deps=
     flake8
-commands=
-    flake8 --exclude=".*" --ignore=E402 flask_paranoid tests
 
 [testenv:docs]
-basepython=python2.7
 changedir=docs
 deps=
     sphinx
@@ -32,4 +32,3 @@
     make
 commands=
     make html
-

Reply via email to