diff --git a/babybuddy/middleware.py b/babybuddy/middleware.py index 2f04150f..d374f099 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,25 @@ 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 (ValueError, TypeError): + 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. 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/')