From c7424612d7c0447373dce8d69aa5af03aebe08dc Mon Sep 17 00:00:00 2001 From: Brett Smith Date: Sun, 24 Mar 2013 14:44:41 -0400 Subject: [PATCH] Back sessions with It's Dangerous. This is a contribution to #668. --- mediagoblin/app.py | 7 +++-- mediagoblin/tools/request.py | 2 +- mediagoblin/tools/session.py | 60 ++++++++++++++++++++++++++++++++++++ setup.py | 1 + 4 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 mediagoblin/tools/session.py diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 515b5b66..fe8e8c4b 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -25,7 +25,7 @@ from werkzeug.exceptions import HTTPException from werkzeug.routing import RequestRedirect from mediagoblin import meddleware, __version__ -from mediagoblin.tools import common, translate, template +from mediagoblin.tools import common, session, translate, template from mediagoblin.tools.response import render_http_exception from mediagoblin.tools.theme import register_themes from mediagoblin.tools import request as mg_request @@ -160,7 +160,8 @@ class MediaGoblinApp(object): ## Attach utilities to the request object # Do we really want to load this via middleware? Maybe? - request.session = request.environ['beaker.session'] + session_manager = session.SessionManager() + request.session = session_manager.load_session_from_cookie(request) # Attach self as request.app # Also attach a few utilities from request.app for convenience? request.app = self @@ -229,6 +230,8 @@ class MediaGoblinApp(object): response = render_http_exeption( request, e, e.get_description(environ)) + session_manager.save_session_to_cookie(request.session, response) + return response(environ, start_response) def __call__(self, environ, start_response): diff --git a/mediagoblin/tools/request.py b/mediagoblin/tools/request.py index bc67b96f..ee342eae 100644 --- a/mediagoblin/tools/request.py +++ b/mediagoblin/tools/request.py @@ -35,4 +35,4 @@ def setup_user_in_request(request): # Something's wrong... this user doesn't exist? Invalidate # this session. _log.warn("Killing session for user id %r", request.session['user_id']) - request.session.invalidate() + request.session.delete() diff --git a/mediagoblin/tools/session.py b/mediagoblin/tools/session.py new file mode 100644 index 00000000..676bc43e --- /dev/null +++ b/mediagoblin/tools/session.py @@ -0,0 +1,60 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import itsdangerous +import logging + +import crypto + +_log = logging.getLogger(__name__) + +class Session(dict): + def save(self): + self.send_new_cookie = True + + def is_updated(self): + return getattr(self, 'send_new_cookie') + + def delete(self): + self.clear() + self.save() + + +class SessionManager(object): + def __init__(self, cookie_name='MGSession', namespace=None): + if namespace is None: + namespace = cookie_name + self.signer = crypto.get_timed_signer_url(namespace) + self.cookie_name = cookie_name + + def load_session_from_cookie(self, request): + cookie = request.cookies.get(self.cookie_name) + if not cookie: + return Session() + ### FIXME: Future cookie-blacklisting code + # m = BadCookie.query.filter_by(cookie = cookie) + # if m: + # _log.warn("Bad cookie received: %s", m.reason) + # raise BadRequest() + try: + return Session(self.signer.loads(cookie)) + except itsdangerous.BadData: + return Session() + + def save_session_to_cookie(self, session, response): + if not session.is_updated: + return + response.set_cookie(self.cookie_name, self.signer.dumps(session)) diff --git a/setup.py b/setup.py index 9c295dc4..3593604e 100644 --- a/setup.py +++ b/setup.py @@ -60,6 +60,7 @@ setup( 'sqlalchemy>=0.7.0', 'sqlalchemy-migrate', 'mock', + 'itsdangerous', ## This is optional! # 'translitcodec', ## For now we're expecting that users will install this from -- 2.25.1