|
@@ -1,44 +1,150 @@
|
1
|
1
|
# -*- coding: utf-8 -*-
|
2
|
2
|
|
3
|
|
-from lodel.plugin import LodelHook
|
|
3
|
+import binascii
|
|
4
|
+import copy
|
|
5
|
+import datetime
|
|
6
|
+import os
|
|
7
|
+import pickle
|
|
8
|
+import re
|
|
9
|
+import time
|
4
|
10
|
|
5
|
|
-from .filesystem_session_store import FileSystemSession
|
|
11
|
+from lodel import logger
|
|
12
|
+from lodel.settings import Settings
|
|
13
|
+from lodel.auth.exceptions import ClientAuthenticationFailure
|
6
|
14
|
|
7
|
|
-## @brief starts a new session and returns its sid
|
8
|
|
-# @param caller *
|
9
|
|
-# @param payload dict
|
|
15
|
+from .filesystem_session import FileSystemSession
|
|
16
|
+
|
|
17
|
+## @brief lists the active sessions in a dict
|
|
18
|
+# Its keys are the session tokens and its values are the file paths of session
|
|
19
|
+# files.
|
|
20
|
+__sessions = dict()
|
|
21
|
+
|
|
22
|
+# ====== UTILS ====== #
|
|
23
|
+
|
|
24
|
+## @brief Generates a session token
|
|
25
|
+# @return str
|
|
26
|
+def __generate_token():
|
|
27
|
+ new_token = binascii.hexlify(os.urandom(Settings.sessions.tokensize//2))
|
|
28
|
+ if new_token in __sessions.keys():
|
|
29
|
+ new_token = __generate_token()
|
|
30
|
+ return new_token
|
|
31
|
+
|
|
32
|
+## @brief Checks if a token is valid and matchs with a registered session
|
|
33
|
+# @param token str
|
|
34
|
+# @raise ClientAuthenticationFailure for invalid or not found session token
|
|
35
|
+def _check_token(token):
|
|
36
|
+ # Bad length
|
|
37
|
+ if len(token) != Settings.sessions.tokensize:
|
|
38
|
+ raise ClientAuthenticationFailure("Malformed session token")
|
|
39
|
+ # Not found
|
|
40
|
+ if token not in __sessions:
|
|
41
|
+ raise ClientAuthenticationFailure("No session found with this token")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+## @brief Lists all the session files' paths
|
|
45
|
+# @return list
|
|
46
|
+def _list_all_sessions():
|
|
47
|
+ session_files_directory = os.abspath(Settings.sessions.directory)
|
|
48
|
+ return [file_path for file_path in os.listdir(session_files_directory) if os.path.isfile(os.path.join(session_files_directory, file_path))]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+## @brief Returns the token from a session file's name
|
|
52
|
+# @param filename str
|
|
53
|
+# @return str
|
|
54
|
+def _get_token_from_session_filename(filename):
|
|
55
|
+ token_regex = re.compile(Settings.sessions.file_template % '(?P<token>.*)')
|
|
56
|
+ token_searching_result = token_regex.match(filename)
|
|
57
|
+ if token_searching_result is not None:
|
|
58
|
+ return token_searching_result.groupdict()['token']
|
|
59
|
+ return None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+## @brief Defines a session file name from a token
|
|
63
|
+# @param token str
|
|
64
|
+# @return str
|
|
65
|
+def _generate_filename_from_token(token):
|
|
66
|
+ return Settings.sessions.file_template % token
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+## @brief Defines a session file path from a token
|
|
70
|
+# @param token str
|
|
71
|
+# @return str
|
|
72
|
+def _generate_filepath_from_token(token):
|
|
73
|
+ return os.path.join(Settings.sessions.directory, Settings.sessions.file_template) % token
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+## @brief Returns the session's last modification timestamp
|
|
77
|
+# @param token str
|
|
78
|
+# @return float
|
|
79
|
+def _get_session_last_modified(token):
|
|
80
|
+ if token in __sessions.keys():
|
|
81
|
+ return os.stat(__sessions[token]).st_mtime
|
|
82
|
+ else:
|
|
83
|
+ raise ValueError("The given token %s doesn't match with an existing session")
|
|
84
|
+
|
|
85
|
+# ====== SESSION MANAGEMENT ====== #
|
|
86
|
+## @brief Registers the session in the active sessions' list
|
|
87
|
+# @param session LodelSession
|
|
88
|
+def _register_session(token):
|
|
89
|
+ __sessions[token] = os.path.join(Settings.sessions.directory, _generate_filename_from_token(token))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+## @brief Session store's garbage collector
|
|
93
|
+def gc():
|
|
94
|
+ # unregistered files in the session directory
|
|
95
|
+ sessions_dir_files = _list_all_sessions()
|
|
96
|
+ for sessions_dir_file in sessions_dir_files:
|
|
97
|
+ token = _get_token_from_session_filename(sessions_dir_file)
|
|
98
|
+ if token is None or token not in __sessions.keys():
|
|
99
|
+ os.unlink(sessions_dir_file)
|
|
100
|
+
|
|
101
|
+ # expired registered sessions
|
|
102
|
+ for token in __sessions.keys():
|
|
103
|
+ if os.path.isfile(__sessions[token]):
|
|
104
|
+ now_timestamp = time.mktime(datetime.datetime.now().timetuple())
|
|
105
|
+ if now_timestamp - _get_session_last_modified(token) > Settings.sessions.expiration:
|
|
106
|
+ destroy_session(token)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+## @brief starts a new session and returns its token
|
10
|
110
|
# @return str
|
11
|
111
|
def start_session():
|
12
|
|
- new_session = FileSystemSession()
|
13
|
|
- return new_session.sid
|
14
|
|
-
|
15
|
|
-## @brief destroys a session
|
16
|
|
-# @param caller *
|
17
|
|
-# @param sid str : session id
|
18
|
|
-def destroy_session(sid):
|
19
|
|
- FileSystemSession.destroy(sid)
|
20
|
|
-
|
21
|
|
-## @brief reads a session content
|
22
|
|
-# @param caller *
|
23
|
|
-# @param sid str: session id
|
|
112
|
+ new_token = __generate_token()
|
|
113
|
+ new_session = FileSystemSession(new_token)
|
|
114
|
+ new_session.save()
|
|
115
|
+ _register_session(new_token)
|
|
116
|
+ _check_token(new_token)
|
|
117
|
+ logger.debug("New session created")
|
|
118
|
+ return new_token
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+## @brief destroys a session defined by its token
|
|
122
|
+# @param token str
|
|
123
|
+def destroy_session(token):
|
|
124
|
+ _check_token(token)
|
|
125
|
+ if os.path.isfile(__sessions[token]):
|
|
126
|
+ os.unlink(__sessions[token])
|
|
127
|
+ del(__sessions[token])
|
|
128
|
+ logger.debug("Session %s destroyed" % token)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+## @brief restores a session's content
|
|
132
|
+# @param token str
|
24
|
133
|
# @return FileSystemSession
|
25
|
|
-def restore_session(sid):
|
26
|
|
- return FileSystemSession.load(sid)
|
27
|
|
-
|
28
|
|
-##@brief Set a session value
|
29
|
|
-#@param name str : session variable name
|
30
|
|
-#@param value mixed : session variable value
|
31
|
|
-def set_value(name, value):
|
32
|
|
- pass
|
33
|
|
-
|
34
|
|
-##@brief Get a session value
|
35
|
|
-#@param name str : the session variable name
|
36
|
|
-#@return the value
|
37
|
|
-def get_value(name):
|
38
|
|
- pass
|
39
|
|
-
|
40
|
|
-##@brief Delete a session value
|
41
|
|
-#@param name str : the session variable name
|
42
|
|
-def del_value(name):
|
43
|
|
- pass
|
44
|
|
-
|
|
134
|
+def restore_session(token):
|
|
135
|
+ _check_token(token)
|
|
136
|
+ logger.debug("Restoring session : %s" % token)
|
|
137
|
+ if os.path.isfile(__sessions[token]):
|
|
138
|
+ with open(__sessions[token], 'rb') as session_file:
|
|
139
|
+ session = pickle.load(session_file)
|
|
140
|
+ return session
|
|
141
|
+ return None
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+def save_session(token, datas=None):
|
|
145
|
+ _check_token(token)
|
|
146
|
+ session = restore_session(token)
|
|
147
|
+ session.datas = copy.copy(datas)
|
|
148
|
+ with open(__sessions[token], 'wb') as session_file:
|
|
149
|
+ pickle.dump(session, session_file)
|
|
150
|
+ logger.debug("Session %s saved" % token)
|