5
6
from django.conf import settings
6
from django.contrib.sessions.backends.base import SessionBase, CreateError
7
from django.contrib.sessions.backends.base import SessionBase, CreateError, VALID_KEY_CHARS
7
8
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
9
from django.utils import timezone
10
11
class SessionStore(SessionBase):
12
13
Implements a file based session store.
14
15
def __init__(self, session_key=None):
15
self.storage_path = getattr(settings, "SESSION_FILE_PATH", None)
16
if not self.storage_path:
17
self.storage_path = tempfile.gettempdir()
19
# Make sure the storage path is valid.
20
if not os.path.isdir(self.storage_path):
21
raise ImproperlyConfigured(
22
"The session storage path %r doesn't exist. Please set your"
23
" SESSION_FILE_PATH setting to an existing directory in which"
24
" Django can store session data." % self.storage_path)
16
self.storage_path = type(self)._get_storage_path()
26
17
self.file_prefix = settings.SESSION_COOKIE_NAME
27
18
super(SessionStore, self).__init__(session_key)
29
VALID_KEY_CHARS = set("abcdef0123456789")
21
def _get_storage_path(cls):
23
return cls._storage_path
24
except AttributeError:
25
storage_path = getattr(settings, "SESSION_FILE_PATH", None)
27
storage_path = tempfile.gettempdir()
29
# Make sure the storage path is valid.
30
if not os.path.isdir(storage_path):
31
raise ImproperlyConfigured(
32
"The session storage path %r doesn't exist. Please set your"
33
" SESSION_FILE_PATH setting to an existing directory in which"
34
" Django can store session data." % storage_path)
36
cls._storage_path = storage_path
31
39
def _key_to_file(self, session_key=None):
38
46
# Make sure we're not vulnerable to directory traversal. Session keys
39
47
# should always be md5s, so they should never contain directory
41
if not set(session_key).issubset(self.VALID_KEY_CHARS):
49
if not set(session_key).issubset(set(VALID_KEY_CHARS)):
42
50
raise SuspiciousOperation(
43
51
"Invalid characters in session key")
45
53
return os.path.join(self.storage_path, self.file_prefix + session_key)
55
def _last_modification(self):
57
Return the modification time of the file storing the session's content.
59
modification = os.stat(self._key_to_file()).st_mtime
61
modification = datetime.datetime.utcfromtimestamp(modification)
62
modification = modification.replace(tzinfo=timezone.utc)
64
modification = datetime.datetime.fromtimestamp(modification)
50
session_file = open(self._key_to_file(), "rb")
70
with open(self._key_to_file(), "rb") as session_file:
52
71
file_data = session_file.read()
53
# Don't fail if there is no data in the session file.
54
# We may have opened the empty placeholder file.
57
session_data = self.decode(file_data)
58
except (EOFError, SuspiciousOperation):
72
# Don't fail if there is no data in the session file.
73
# We may have opened the empty placeholder file.
76
session_data = self.decode(file_data)
77
except (EOFError, SuspiciousOperation):
80
# Remove expired sessions.
81
expiry_age = self.get_expiry_age(
82
modification=self._last_modification(),
83
expiry=session_data.get('_session_expiry'))
64
90
return session_data
121
os.write(output_file_fd, self.encode(session_data))
147
os.write(output_file_fd, self.encode(session_data).encode())
123
149
os.close(output_file_fd)
124
150
os.rename(output_file_name, session_file_name)
176
def clear_expired(cls):
177
storage_path = cls._get_storage_path()
178
file_prefix = settings.SESSION_COOKIE_NAME
180
for session_file in os.listdir(storage_path):
181
if not session_file.startswith(file_prefix):
183
session_key = session_file[len(file_prefix):]
184
session = cls(session_key)
185
# When an expired session is loaded, its file is removed, and a
186
# new file is immediately created. Prevent this by disabling
187
# the create() method.
188
session.create = lambda: None