From fe85970665ea3a38f9c6a8ef4756ff3a913850b6 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sat, 11 Aug 2012 03:38:46 +0100 Subject: [PATCH] Various improvements in regards to the itsdangerous usage, bumped to 0.17 --- flask/sessions.py | 55 ++++++++++++++++++++++++++++++++++------------- setup.py | 2 +- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/flask/sessions.py b/flask/sessions.py index 3db1fb60..ba0b0ed7 100644 --- a/flask/sessions.py +++ b/flask/sessions.py @@ -10,6 +10,7 @@ :license: BSD, see LICENSE for more details. """ +import hashlib from datetime import datetime from werkzeug.http import http_date, parse_date from werkzeug.datastructures import CallbackDict @@ -54,13 +55,13 @@ class TaggedJSONSerializer(object): def dumps(self, value): def _tag(value): if isinstance(value, tuple): - return {'##t': [_tag(x) for x in value]} + return {' t': [_tag(x) for x in value]} elif callable(getattr(value, '__html__', None)): - return {'##m': unicode(value.__html__())} + return {' m': unicode(value.__html__())} elif isinstance(value, list): return [_tag(x) for x in value] elif isinstance(value, datetime): - return {'##d': http_date(value)} + return {' d': http_date(value)} elif isinstance(value, dict): return dict((k, _tag(v)) for k, v in value.iteritems()) return value @@ -71,11 +72,11 @@ class TaggedJSONSerializer(object): if len(obj) != 1: return obj the_key, the_value = obj.iteritems().next() - if the_key == '##t': + if the_key == ' t': return tuple(the_value) - elif the_key == '##m': + elif the_key == ' m': return Markup(the_value) - elif the_key == '##d': + elif the_key == ' d': return parse_date(the_value) return obj return json.loads(value, object_hook=object_hook) @@ -145,6 +146,13 @@ class SessionInterface(object): #: this type. null_session_class = NullSession + #: A flag that indicates if the session interface is pickle based. + #: This can be used by flask extensions to make a decision in regards + #: to how to deal with the session object. + #: + #: .. versionadded:: 0.10 + pickle_based = False + def make_null_session(self, app): """Creates a null session which acts as a replacement object if the real session support could not be loaded due to a configuration @@ -225,19 +233,36 @@ class SessionInterface(object): class SecureCookieSessionInterface(SessionInterface): + """The default session interface that stores sessions in signed cookies + through the :mod:`itsdangerous` module. + """ + #: the salt that should be applied on top of the secret key for the + #: signing of cookie based sessions. salt = 'cookie-session' - session_class = SecureCookieSession + #: the hash function to use for the signature. The default is sha1 + digest_method = staticmethod(hashlib.sha1) + #: the name of the itsdangerous supported key derivation. The default + #: is hmac. + key_derivation = 'hmac' + #: A python serializer for the payload. The default is a compact + #: JSON derived serializer with support for some extra Python types + #: such as datetime objects or tuples. serializer = session_json_serializer + session_class = SecureCookieSession - def get_serializer(self, app): + def get_signing_serializer(self, app): if not app.secret_key: return None - return URLSafeTimedSerializer(app.secret_key, - salt=self.salt, - serializer=self.serializer) + signer_kwargs = dict( + key_derivation=self.key_derivation, + digest_method=self.digest_method + ) + return URLSafeTimedSerializer(app.secret_key, salt=self.salt, + serializer=self.serializer, + signer_kwargs=signer_kwargs) def open_session(self, app, request): - s = self.get_serializer(app) + s = self.get_signing_serializer(app) if s is None: return None val = request.cookies.get(app.session_cookie_name) @@ -253,15 +278,15 @@ class SecureCookieSessionInterface(SessionInterface): def save_session(self, app, session, response): domain = self.get_cookie_domain(app) path = self.get_cookie_path(app) - httponly = self.get_cookie_httponly(app) - secure = self.get_cookie_secure(app) if not session: if session.modified: response.delete_cookie(app.session_cookie_name, domain=domain, path=path) return + httponly = self.get_cookie_httponly(app) + secure = self.get_cookie_secure(app) expires = self.get_expiration_time(app, session) - val = self.get_serializer(app).dumps(dict(session)) + val = self.get_signing_serializer(app).dumps(dict(session)) response.set_cookie(app.session_cookie_name, val, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure) diff --git a/setup.py b/setup.py index 0225e5fc..4a9182b9 100644 --- a/setup.py +++ b/setup.py @@ -92,7 +92,7 @@ setup( install_requires=[ 'Werkzeug>=0.7', 'Jinja2>=2.4', - 'itsdangerous>=0.16' + 'itsdangerous>=0.17' ], classifiers=[ 'Development Status :: 4 - Beta',