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