Hello community,

here is the log from the commit of package python-Beaker for openSUSE:Factory 
checked in at 2019-09-25 08:26:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-Beaker (Old)
 and      /work/SRC/openSUSE:Factory/.python-Beaker.new.7948 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-Beaker"

Wed Sep 25 08:26:32 2019 rev:24 rq:732776 version:1.11.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-Beaker/python-Beaker.changes      
2019-04-19 18:39:11.719246611 +0200
+++ /work/SRC/openSUSE:Factory/.python-Beaker.new.7948/python-Beaker.changes    
2019-09-25 08:26:33.490399551 +0200
@@ -1,0 +2,9 @@
+Mon Sep 23 14:43:25 UTC 2019 - [email protected]
+
+- version update to 1.11.0
+  * Fixed cookie path option not being properly set (`self._path`
+    was removed, only `self.path` exists)
+  * Documented `SameSite` option
+  * Fixed cookie expiration being localised when it shouldn't.
+
+-------------------------------------------------------------------

Old:
----
  1.10.1.tar.gz

New:
----
  1.11.0.tar.gz

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

Other differences:
------------------
++++++ python-Beaker.spec ++++++
--- /var/tmp/diff_new_pack.hHn6Ef/_old  2019-09-25 08:26:33.910399493 +0200
+++ /var/tmp/diff_new_pack.hHn6Ef/_new  2019-09-25 08:26:33.910399493 +0200
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define oldpython python
 Name:           python-Beaker
-Version:        1.10.1
+Version:        1.11.0
 Release:        0
 Summary:        A Session and Caching library with WSGI Middleware
 License:        BSD-3-Clause
@@ -44,6 +44,7 @@
 BuildRequires:  python3-dbm
 Requires:       python-pylibmc
 Requires:       python-python-memcached
+Requires:       python-setuptools
 Recommends:     python-SQLAlchemy
 Recommends:     python-cryptography
 Recommends:     python-pycrypto

++++++ 1.10.1.tar.gz -> 1.11.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/beaker-1.10.1/.travis.yml 
new/beaker-1.11.0/.travis.yml
--- old/beaker-1.10.1/.travis.yml       2019-02-21 20:42:27.000000000 +0100
+++ new/beaker-1.11.0/.travis.yml       2019-08-26 23:52:26.000000000 +0200
@@ -2,6 +2,11 @@
 os:
   - linux
 dist: xenial
+addons:
+  apt:
+    packages:
+      - language-pack-it
+      - locales
 services:
   - mongodb
   - memcached
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/beaker-1.10.1/CHANGELOG new/beaker-1.11.0/CHANGELOG
--- old/beaker-1.10.1/CHANGELOG 2019-02-21 20:42:27.000000000 +0100
+++ new/beaker-1.11.0/CHANGELOG 2019-08-26 23:52:26.000000000 +0200
@@ -1,4 +1,11 @@
 
+Release 1.11.0 (2019-08-26)
+===========================
+
+* Fixed cookie path option not being properly set (`self._path` was removed, 
only `self.path` exists)
+* Documented `SameSite` option
+* Fixed cookie expiration being localised when it shouldn't. 
+
 Release 1.10.1 (2019-02-21)
 ===========================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/beaker-1.10.1/beaker/__init__.py 
new/beaker-1.11.0/beaker/__init__.py
--- old/beaker-1.10.1/beaker/__init__.py        2019-02-21 20:42:27.000000000 
+0100
+++ new/beaker-1.11.0/beaker/__init__.py        2019-08-26 23:52:26.000000000 
+0200
@@ -1 +1 @@
-__version__ = '1.10.1'
+__version__ = '1.11.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/beaker-1.10.1/beaker/docs/configuration.rst 
new/beaker-1.11.0/beaker/docs/configuration.rst
--- old/beaker-1.10.1/beaker/docs/configuration.rst     2019-02-21 
20:42:27.000000000 +0100
+++ new/beaker-1.11.0/beaker/docs/configuration.rst     2019-08-26 
23:52:26.000000000 +0200
@@ -111,9 +111,10 @@
     the environ for use with WebTest. The name provided here is where the
     session object will be attached to the WebTest TestApp return value.
 
-url (**optional**, string) URL is specific to use of either ``ext:memcached``,
-    ``ext:database``, ``ext:mongodb``, or ``ext:redis``. When using one of 
those
-    types, this option is **required**.
+url (**optional**, string)
+    URL is specific to use of either ``ext:memcached``, ``ext:database``,
+    ``ext:mongodb``, or ``ext:redis``. When using one of those types, this
+    option is **required**.
 
     When used with ``ext:memcached``, this should be either a single, or
     semi-colon separated list of memcached servers::
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/beaker-1.10.1/beaker/docs/sessions.rst 
new/beaker-1.11.0/beaker/docs/sessions.rst
--- old/beaker-1.10.1/beaker/docs/sessions.rst  2019-02-21 20:42:27.000000000 
+0100
+++ new/beaker-1.11.0/beaker/docs/sessions.rst  2019-08-26 23:52:26.000000000 
+0200
@@ -224,18 +224,21 @@
 ======================
 
 Beaker uses the defaults of setting cookie attributes `httponly` and `secure`
-to False. You may want to set those to True in production, and the reasons for
+to False. You may want to set those to True in production. `samesite` also 
setting
+with default value `Lax`, you can choice `Strict` for more protection. And the 
reasons for
 using these cookie attributes are explained in these Owasp guides - `HttpOnly`_
-, `SecureFlag`_.
+, `SecureFlag`_, `SameSite`_.
 
 Example::
 
     # Best practice cookie flags for security
     session.httponly = True
     session.secure = True
+    session.samesite = 'Lax' # or 'Strict'
 
 .. _SecureFlag: https://www.owasp.org/index.php/SecureFlag
 .. _HttpOnly: 
https://www.owasp.org/index.php/HttpOnly#Mitigating_the_Most_Common_XSS_attack_using_HttpOnly
+.. _SameSite: https://www.owasp.org/index.php/SameSite
 
 Cookie-Based
 ============
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/beaker-1.10.1/beaker/session.py 
new/beaker-1.11.0/beaker/session.py
--- old/beaker-1.10.1/beaker/session.py 2019-02-21 20:42:27.000000000 +0100
+++ new/beaker-1.11.0/beaker/session.py 2019-08-26 23:52:26.000000000 +0200
@@ -9,6 +9,12 @@
 from beaker.exceptions import BeakerException, InvalidCryptoBackendError
 from beaker.cookie import SimpleCookie
 
+
+months = (None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
+weekdays = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
+
+
 __all__ = ['SignedCookie', 'Session', 'InvalidSignature']
 
 
@@ -86,7 +92,27 @@
         return str(val), ("%s%s" % (sig, val))
 
 
-class Session(dict):
+class _ConfigurableSession(dict):
+    """Provides support for configurable Session objects.
+    
+    Provides a way to ensure some properties of sessions
+    are always available with pre-configured values
+    when they are not available in the session cookie itself.
+    """
+
+    def __init__(self, cookie_domain=None, cookie_path='/'):
+        self._config = {
+            '_domain': cookie_domain,
+            '_path': cookie_path
+        }
+
+    def clear(self):
+        """Clears Session data. Preserves session configuration."""
+        super(_ConfigurableSession, self).clear()
+        self.update(self._config)
+
+
+class Session(_ConfigurableSession):
     """Session object that uses container package for storage.
 
     :param invalidate_corrupt: How to handle corrupt data when loading. When
@@ -139,6 +165,13 @@
                  encrypt_key=None, validate_key=None, 
encrypt_nonce_bits=DEFAULT_NONCE_BITS,
                  crypto_type='default', samesite='Lax',
                  **namespace_args):
+        _ConfigurableSession.__init__(
+            self,
+            cookie_domain=cookie_domain,
+            cookie_path=cookie_path
+        )
+        self.clear()
+        
         if not type:
             if data_dir:
                 self.type = 'file'
@@ -174,8 +207,6 @@
         self._set_serializer(data_serializer)
 
         # Default cookie domain/path
-        self._domain = cookie_domain
-        self._path = cookie_path
         self.was_invalidated = False
         self.secret = secret
         self.secure = secure
@@ -245,17 +276,24 @@
 
     def _set_cookie_values(self, expires=None):
         self.cookie[self.key] = self.id
-        if self._domain:
-            self.cookie[self.key]['domain'] = self._domain
+        if self.domain:
+            self.cookie[self.key]['domain'] = self.domain
         if self.secure:
             self.cookie[self.key]['secure'] = True
         if self.samesite:
             self.cookie[self.key]['samesite'] = self.samesite
         self._set_cookie_http_only()
-        self.cookie[self.key]['path'] = self._path
+        self.cookie[self.key]['path'] = self.path
 
         self._set_cookie_expires(expires)
 
+    @staticmethod
+    def serialize_cookie_date(v):
+        v = v.timetuple()
+        r = time.strftime("%%s, %d-%%s-%Y %H:%M:%S GMT", v)
+        return r % (weekdays[v[6]], months[v[1]])
+
+        
     def _set_cookie_expires(self, expires):
         if expires is None:
             expires = self.cookie_expires
@@ -275,12 +313,15 @@
             self.cookie[self.key]['expires'] = ''
             return True
         self.cookie[self.key]['expires'] = \
-            expires_date.strftime("%a, %d-%b-%Y %H:%M:%S GMT")
+            self.serialize_cookie_date(expires_date)
         return expires_date
 
     def _update_cookie_out(self, set_cookie=True):
         self._set_cookie_values()
-        self.request['cookie_out'] = self.cookie[self.key].output(header='')
+        cookie_out = self.cookie[self.key].output(header='')
+        if not isinstance(cookie_out, str):
+            cookie_out = cookie_out.encode('latin1')
+        self.request['cookie_out'] = cookie_out
         self.request['set_cookie'] = set_cookie
 
     def _set_cookie_http_only(self):
@@ -307,20 +348,20 @@
         return self['_creation_time']
 
     def _set_domain(self, domain):
-        self['_domain'] = self._domain = domain
+        self['_domain'] = domain
         self._update_cookie_out()
 
     def _get_domain(self):
-        return self._domain
+        return self['_domain']
 
     domain = property(_get_domain, _set_domain)
 
     def _set_path(self, path):
-        self['_path'] = self._path = path
+        self['_path'] = path
         self._update_cookie_out()
 
     def _get_path(self):
-        return self._path
+        return self.get('_path', '/')
 
     path = property(_get_path, _set_path)
 
@@ -434,9 +475,6 @@
                 # Update the current _accessed_time
                 session_data['_accessed_time'] = now
 
-                # Set the path if applicable
-                if '_path' in session_data:
-                    self._path = session_data['_path']
                 self.update(session_data)
                 self.accessed_dict = session_data.copy()
         finally:
@@ -571,6 +609,12 @@
                  encrypt_nonce_bits=DEFAULT_NONCE_BITS, 
invalidate_corrupt=False,
                  crypto_type='default', samesite='Lax',
                  **kwargs):
+        _ConfigurableSession.__init__(
+            self,
+            cookie_domain=cookie_domain,
+            cookie_path=cookie_path
+        )
+        self.clear()
 
         self.crypto_module = get_crypto_module(crypto_type)
 
@@ -590,8 +634,6 @@
         self.secure = secure
         self.httponly = httponly
         self.samesite = samesite
-        self._domain = cookie_domain
-        self._path = cookie_path
         self.invalidate_corrupt = invalidate_corrupt
         self._set_serializer(data_serializer)
 
@@ -628,7 +670,6 @@
                 if cookie_data is InvalidSignature:
                     raise BeakerException("Invalid signature")
                 self.update(self._decrypt_data(cookie_data))
-                self._path = self.get('_path', '/')
             except Exception as e:
                 if self.invalidate_corrupt:
                     util.warn(
@@ -658,18 +699,17 @@
 
     def _set_domain(self, domain):
         self['_domain'] = domain
-        self._domain = domain
 
     def _get_domain(self):
-        return self._domain
+        return self['_domain']
 
     domain = property(_get_domain, _set_domain)
 
     def _set_path(self, path):
-        self['_path'] = self._path = path
+        self['_path'] = path
 
     def _get_path(self):
-        return self._path
+        return self['_path']
 
     path = property(_get_path, _set_path)
 
@@ -708,10 +748,8 @@
         if expires is not None:
             self['_expires'] = expires
 
-        if '_domain' in self:
-            self.cookie[self.key]['domain'] = self['_domain']
-        elif self._domain:
-            self.cookie[self.key]['domain'] = self._domain
+        if self.domain:
+            self.cookie[self.key]['domain'] = self.domain
         if self.secure:
             self.cookie[self.key]['secure'] = True
         if self.samesite:
@@ -720,7 +758,10 @@
 
         self.cookie[self.key]['path'] = self.get('_path', '/')
 
-        self.request['cookie_out'] = self.cookie[self.key].output(header='')
+        cookie_out = self.cookie[self.key].output(header='')
+        if not isinstance(cookie_out, str):
+            cookie_out = cookie_out.encode('latin1')
+        self.request['cookie_out'] = cookie_out
         self.request['set_cookie'] = True
 
     def delete(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/beaker-1.10.1/tests/test_cookie_expires.py 
new/beaker-1.11.0/tests/test_cookie_expires.py
--- old/beaker-1.10.1/tests/test_cookie_expires.py      2019-02-21 
20:42:27.000000000 +0100
+++ new/beaker-1.11.0/tests/test_cookie_expires.py      2019-08-26 
23:52:26.000000000 +0200
@@ -56,6 +56,17 @@
 
     assert no_expires is False, no_expires
 
+def test_cookie_expires_different_locale():
+    from locale import setlocale, LC_TIME
+    expires_date = datetime.datetime(2019, 5, 22)
+    setlocale(LC_TIME, 'it_IT.UTF-8')
+    # if you get locale.Error: unsupported locale setting. you have to enable 
that locale in your OS.
+    assert expires_date.strftime("%a, %d-%b-%Y %H:%M:%S 
GMT").startswith('mer,')
+    session = Session({}, cookie_expires=True, validate_key='validate_key')
+    assert session._set_cookie_expires(expires_date)
+    expires = cookie_expiration(session)
+    assert expires == 'Wed, 22-May-2019 00:00:00 GMT', expires
+    setlocale(LC_TIME, '')  # restore default locale for further tests
 
 def test_set_cookie_expires():
     """Exhibit Set-Cookie: values."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/beaker-1.10.1/tests/test_cookie_only.py 
new/beaker-1.11.0/tests/test_cookie_only.py
--- old/beaker-1.10.1/tests/test_cookie_only.py 2019-02-21 20:42:27.000000000 
+0100
+++ new/beaker-1.11.0/tests/test_cookie_only.py 2019-08-26 23:52:26.000000000 
+0200
@@ -315,6 +315,61 @@
     assert 'httponly' in cookie.lower()
     assert 'samesite=strict' in cookie.lower()
 
+
+def test_cookie_path_properly_set_after_init():
+    COOKIE_PATH = '/app'
+
+    options = {
+        'session.validate_key': 'hoobermas',
+        'session.type': 'cookie',
+        'session.cookie_path': COOKIE_PATH,
+    }
+    app = TestApp(SessionMiddleware(simple_app, **options))
+    res = app.get('/app')
+    cookie = res.headers['Set-Cookie']
+
+    assert ('path=%s' % COOKIE_PATH) in cookie.lower()
+
+
+def test_cookie_path_properly_set_after_load():
+    COOKIE_PATH = '/app'
+
+    options = {
+        'session.validate_key': 'hoobermas',
+        'session.type': 'cookie',
+        'session.cookie_path': COOKIE_PATH,
+    }
+    app = TestApp(SessionMiddleware(simple_app, **options))
+    # Perform one request to set the cookie
+    res = app.get('/app')
+    # Perform another request to load the previous session from the cookie
+    res = app.get('/app')
+    cookie = res.headers['Set-Cookie']
+
+    assert ('path=%s' % COOKIE_PATH) in cookie.lower()
+
+
+def test_cookie_path_properly_set_after_delete():
+    COOKIE_PATH = '/app'
+
+    def delete_session_app(environ, start_response):
+        session = environ['beaker.session']
+        session.delete()
+        start_response('200 OK', [('Content-type', 'text/plain')])
+        return [('Cookie is %s' % session).encode('UTF-8')]
+
+    options = {
+        'session.validate_key': 'hoobermas',
+        'session.type': 'cookie',
+        'session.cookie_path': COOKIE_PATH,
+    }
+    app = TestApp(SessionMiddleware(delete_session_app, **options))
+    res = app.get('/app')
+    cookie = res.headers['Set-Cookie']
+
+    assert ('path=%s' % COOKIE_PATH) in cookie.lower()
+
+
 if __name__ == '__main__':
     from paste import httpserver
     wsgi_app = SessionMiddleware(simple_app, {})


Reply via email to