From 1d9a7d4215ddc1bc2bc3409cdd06ad727b8afab4 Mon Sep 17 00:00:00 2001 From: Peter Hardy Date: Sun, 17 May 2020 16:57:00 +1000 Subject: [PATCH 1/2] Adds rolling session refresh middleware (#130) --- babybuddy/middleware.py | 24 ++++++++++++++++++++++++ babybuddy/settings/base.py | 5 +++++ 2 files changed, 29 insertions(+) diff --git a/babybuddy/middleware.py b/babybuddy/middleware.py index 2f04150f..97db0bc5 100644 --- a/babybuddy/middleware.py +++ b/babybuddy/middleware.py @@ -1,5 +1,8 @@ +import time + import pytz +from django.conf import settings from django.utils import timezone @@ -19,3 +22,24 @@ class UserTimezoneMiddleware: except pytz.UnknownTimeZoneError: pass return self.get_response(request) + +class RollingSessionMiddleware: + """ + Periodically resets the session expiry. + """ + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + session_refresh = request.session.get('session_refresh') + if session_refresh: + try: + delta = int(time.time()) - session_refresh + except: + delta = settings.ROLLING_SESSION_REFRESH + 1 + if delta > settings.ROLLING_SESSION_REFRESH: + request.session['session_refresh'] = int(time.time()) + request.session.set_expiry(settings.SESSION_COOKIE_AGE) + else: + request.session['session_refresh'] = int(time.time()) + return self.get_response(request) diff --git a/babybuddy/settings/base.py b/babybuddy/settings/base.py index bcbed6c5..6acc0b85 100644 --- a/babybuddy/settings/base.py +++ b/babybuddy/settings/base.py @@ -58,6 +58,7 @@ MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'babybuddy.middleware.RollingSessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'babybuddy.middleware.UserTimezoneMiddleware', 'django.middleware.common.CommonMiddleware', @@ -223,6 +224,10 @@ IMPORT_EXPORT_IMPORT_PERMISSION_CODE = 'add' IMPORT_EXPORT_EXPORT_PERMISSION_CODE = 'change' IMPORT_EXPORT_USE_TRANSACTIONS = True +# Rolling session refreshes +# How often to refresh the session +ROLLING_SESSION_REFRESH = 86400 + # Baby Buddy configuration # See README.md#configuration for details about these settings. From 2806d0a22f43156f41c26a0807b1ed1740764b2d Mon Sep 17 00:00:00 2001 From: Peter Hardy Date: Sun, 17 May 2020 20:11:08 +1000 Subject: [PATCH 2/2] The rest of the middleware commit --- babybuddy/middleware.py | 3 ++- babybuddy/settings/development.py | 2 ++ babybuddy/tests/tests_views.py | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/babybuddy/middleware.py b/babybuddy/middleware.py index 97db0bc5..d374f099 100644 --- a/babybuddy/middleware.py +++ b/babybuddy/middleware.py @@ -23,6 +23,7 @@ class UserTimezoneMiddleware: pass return self.get_response(request) + class RollingSessionMiddleware: """ Periodically resets the session expiry. @@ -35,7 +36,7 @@ class RollingSessionMiddleware: if session_refresh: try: delta = int(time.time()) - session_refresh - except: + except (ValueError, TypeError): delta = settings.ROLLING_SESSION_REFRESH + 1 if delta > settings.ROLLING_SESSION_REFRESH: request.session['session_refresh'] = int(time.time()) diff --git a/babybuddy/settings/development.py b/babybuddy/settings/development.py index 2ef9185c..d13b9eb4 100644 --- a/babybuddy/settings/development.py +++ b/babybuddy/settings/development.py @@ -35,3 +35,5 @@ REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'] = ( 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ) + +ROLLING_SESSION_REFRESH = 1 diff --git a/babybuddy/tests/tests_views.py b/babybuddy/tests/tests_views.py index 4ff2a464..b3ffad34 100644 --- a/babybuddy/tests/tests_views.py +++ b/babybuddy/tests/tests_views.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +import time + from django.test import TestCase from django.test import Client as HttpClient from django.contrib.auth.models import User @@ -30,6 +32,19 @@ class ViewsTestCase(TestCase): page = self.c.get('/') self.assertEqual(page.url, '/dashboard/') + def test_rolling_sessions(self): + self.c.get('/') + session1 = str(self.c.cookies['sessionid']) + # Sleep longer than ROLLING_SESSION_REFRESH in our + # settings module, to test we get a new session. + time.sleep(2) + self.c.get('/') + session2 = str(self.c.cookies['sessionid']) + self.c.get('/') + session3 = str(self.c.cookies['sessionid']) + self.assertNotEqual(session1, session2) + self.assertEqual(session2, session3) + def test_user_reset_api_key(self): api_key_before = User.objects.get(pk=self.user.id).settings.api_key() page = self.c.get('/user/reset-api-key/')