|
|
@ -10,6 +10,7 @@ |
|
|
|
""" |
|
|
|
""" |
|
|
|
import hashlib |
|
|
|
import hashlib |
|
|
|
import warnings |
|
|
|
import warnings |
|
|
|
|
|
|
|
from collections import MutableMapping |
|
|
|
from datetime import datetime |
|
|
|
from datetime import datetime |
|
|
|
|
|
|
|
|
|
|
|
from itsdangerous import BadSignature, URLSafeTimedSerializer |
|
|
|
from itsdangerous import BadSignature, URLSafeTimedSerializer |
|
|
@ -19,52 +20,67 @@ from flask.helpers import is_ip, total_seconds |
|
|
|
from flask.json.tag import TaggedJSONSerializer |
|
|
|
from flask.json.tag import TaggedJSONSerializer |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SessionMixin(object): |
|
|
|
class SessionMixin(MutableMapping): |
|
|
|
"""Expands a basic dictionary with an accessors that are expected |
|
|
|
"""Expands a basic dictionary with session attributes.""" |
|
|
|
by Flask extensions and users for the session. |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _get_permanent(self): |
|
|
|
@property |
|
|
|
|
|
|
|
def permanent(self): |
|
|
|
|
|
|
|
"""This reflects the ``'_permanent'`` key in the dict.""" |
|
|
|
return self.get('_permanent', False) |
|
|
|
return self.get('_permanent', False) |
|
|
|
|
|
|
|
|
|
|
|
def _set_permanent(self, value): |
|
|
|
@permanent.setter |
|
|
|
|
|
|
|
def permanent(self, value): |
|
|
|
self['_permanent'] = bool(value) |
|
|
|
self['_permanent'] = bool(value) |
|
|
|
|
|
|
|
|
|
|
|
#: this reflects the ``'_permanent'`` key in the dict. |
|
|
|
#: Some implementations can track whether a session is new, but |
|
|
|
permanent = property(_get_permanent, _set_permanent) |
|
|
|
#: that is not guaranteed. Use with caution. The mixin default is |
|
|
|
del _get_permanent, _set_permanent |
|
|
|
#: hard-coded ``False``. |
|
|
|
|
|
|
|
|
|
|
|
#: some session backends can tell you if a session is new, but that is |
|
|
|
|
|
|
|
#: not necessarily guaranteed. Use with caution. The default mixin |
|
|
|
|
|
|
|
#: implementation just hardcodes ``False`` in. |
|
|
|
|
|
|
|
new = False |
|
|
|
new = False |
|
|
|
|
|
|
|
|
|
|
|
#: for some backends this will always be ``True``, but some backends will |
|
|
|
#: Some implementations can detect changes to the session and set |
|
|
|
#: default this to false and detect changes in the dictionary for as |
|
|
|
#: this when that happens. The mixin default is hard coded to |
|
|
|
#: long as changes do not happen on mutable structures in the session. |
|
|
|
#: ``True``. |
|
|
|
#: The default mixin implementation just hardcodes ``True`` in. |
|
|
|
|
|
|
|
modified = True |
|
|
|
modified = True |
|
|
|
|
|
|
|
|
|
|
|
#: the accessed variable indicates whether or not the session object has |
|
|
|
#: Some implementations can detect when session data is read or |
|
|
|
#: been accessed in that request. This allows flask to append a `Vary: |
|
|
|
#: written and set this when that happens. The mixin default is hard |
|
|
|
#: Cookie` header to the response if the session is being accessed. This |
|
|
|
#: coded to ``True``. |
|
|
|
#: allows caching proxy servers, like Varnish, to use both the URL and the |
|
|
|
|
|
|
|
#: session cookie as keys when caching pages, preventing multiple users |
|
|
|
|
|
|
|
#: from being served the same cache. |
|
|
|
|
|
|
|
accessed = True |
|
|
|
accessed = True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SecureCookieSession(CallbackDict, SessionMixin): |
|
|
|
class SecureCookieSession(CallbackDict, SessionMixin): |
|
|
|
"""Base class for sessions based on signed cookies.""" |
|
|
|
"""Base class for sessions based on signed cookies. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This session backend will set the :attr:`new`, :attr:`modified`, |
|
|
|
|
|
|
|
and :attr:`accessed` attributes. |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#: The session is considered "new" if there was no session data |
|
|
|
|
|
|
|
#: loaded. This means that the session will be new until there is |
|
|
|
|
|
|
|
#: data in the session, because no cookie will be written otherwise. |
|
|
|
|
|
|
|
new = True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#: When data is changed, this is set to ``True``. Only the session |
|
|
|
|
|
|
|
#: dictionary itself is tracked; if the session contains mutable |
|
|
|
|
|
|
|
#: data (for example a nested dict) then this must be set to |
|
|
|
|
|
|
|
#: ``True`` manually when modifying that data. The session cookie |
|
|
|
|
|
|
|
#: will only be written to the response if this is ``True``. |
|
|
|
|
|
|
|
modified = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#: When data is read or written, this is set to ``True``. Used by |
|
|
|
|
|
|
|
# :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie`` |
|
|
|
|
|
|
|
#: header, which allows caching proxies to cache different pages for |
|
|
|
|
|
|
|
#: different users. |
|
|
|
|
|
|
|
accessed = False |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, initial=None): |
|
|
|
def __init__(self, initial=None): |
|
|
|
|
|
|
|
self.new = initial is None |
|
|
|
|
|
|
|
|
|
|
|
def on_update(self): |
|
|
|
def on_update(self): |
|
|
|
self.modified = True |
|
|
|
self.modified = True |
|
|
|
self.accessed = True |
|
|
|
self.accessed = True |
|
|
|
|
|
|
|
|
|
|
|
super(SecureCookieSession, self).__init__(initial, on_update) |
|
|
|
super(SecureCookieSession, self).__init__(initial, on_update) |
|
|
|
self.modified = False |
|
|
|
|
|
|
|
self.accessed = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, key): |
|
|
|
def __getitem__(self, key): |
|
|
|
self.accessed = True |
|
|
|
self.accessed = True |
|
|
|