Browse Source

Added documentation FS Session

Quentin Bonaventure 7 years ago
parent
commit
69171b23fd
1 changed files with 69 additions and 12 deletions
  1. 69
    12
      lodel/plugins/filesystem_session/main.py

+ 69
- 12
lodel/plugins/filesystem_session/main.py View File

8
 import pickle
8
 import pickle
9
 import re
9
 import re
10
 import time
10
 import time
11
-
11
+from .filesystem_session import FileSystemSession
12
 from lodel.context import LodelContext
12
 from lodel.context import LodelContext
13
+
14
+
13
 LodelContext.expose_modules(globals(), {
15
 LodelContext.expose_modules(globals(), {
14
     'lodel.logger': 'logger',
16
     'lodel.logger': 'logger',
15
     'lodel.auth.exceptions': ['ClientAuthenticationFailure'],
17
     'lodel.auth.exceptions': ['ClientAuthenticationFailure'],
16
     'lodel.settings': ['Settings']})
18
     'lodel.settings': ['Settings']})
17
 
19
 
18
-from .filesystem_session import FileSystemSession
19
-
20
 __sessions = dict()
20
 __sessions = dict()
21
 
21
 
22
 SESSION_TOKENSIZE = 150
22
 SESSION_TOKENSIZE = 150
23
 
23
 
24
 
24
 
25
-## @brief generates a new session token
25
+##
26
+# @brief generates a new session token
27
+#
26
 # @return str
28
 # @return str
29
+#
30
+# @warning The tokensize should absolutely be used as set! os.urandom function
31
+#            takes a number of bytes as a parameter, dividing it by 2 is an
32
+#            extremely dangerous idea as it drastically decrease the token expected 
33
+#            entropy expected from the value set in configs.
34
+# @remarks There is no valid reason for checking the generated token uniqueness:
35
+#        - checking for uniqueness is slow ;
36
+#        - keeping a dict with a few thousand keys of hundred bytes also is
37
+#            memory expensive ;
38
+#        - should the system get distributed while sharing session storage, there
39
+#            would be no reasonable way to efficiently check for uniqueness ;
40
+#        - sessions do have a really short life span, drastically reducing
41
+#            even more an already close to inexistent risk of collision. A 64 bits
42
+#            id would perfectly do the job, or to be really cautious, a 128 bits
43
+#            one (actual size of UUIDs) ;
44
+#        - if we are still willing to ensure uniqueness, then simply salt it
45
+#            with a counter, or a timestamp, and hash the whole thing with a 
46
+#            cryptographically secured method such as sha-2 if we are paranoids
47
+#            and trying to avoid what will never happen, ever ;
48
+#        - sure, two hexadecimal characters is one byte long. Simply go for 
49
+#            bit length, not chars length.
27
 def generate_token():
50
 def generate_token():
28
     token = binascii.hexlify(os.urandom(SESSION_TOKENSIZE//2))
51
     token = binascii.hexlify(os.urandom(SESSION_TOKENSIZE//2))
29
     if token in __sessions.keys():
52
     if token in __sessions.keys():
31
     return token.decode('utf-8')
54
     return token.decode('utf-8')
32
 
55
 
33
 
56
 
34
-## @brief checks the validity of a given session token
57
+##
58
+# @brief checks the validity of a given session token
59
+#
35
 # @param token str
60
 # @param token str
36
-# @throw ClientAuthenticationFailure for invalid or not found session token
61
+# @raise ClientAuthenticationFailure for invalid or not found session token
62
+#
63
+# @remarks It is useless to check the token size, unless urandom you don't
64
+#            trust in PRNG such as urandom.
65
+# @remarks Linear key search...
66
+# @remarks Consider renaming. The "validity of a session token" usually means
67
+#            that it is a active session token and/or that it was actually
68
+#            produced by the application (signed for exemple).
37
 def check_token(token):
69
 def check_token(token):
38
     if len(token) != SESSION_TOKENSIZE:
70
     if len(token) != SESSION_TOKENSIZE:
39
         raise ClientAuthenticationFailure("Invalid token string")
71
         raise ClientAuthenticationFailure("Invalid token string")
49
 
81
 
50
 
82
 
51
 ##
83
 ##
84
+# @brief Retrieve the token from the file system
85
+#
52
 # @param filepath str
86
 # @param filepath str
53
 # @return str|None : returns the token or None if no token was found
87
 # @return str|None : returns the token or None if no token was found
88
+#
89
+# @remarks What is the purpose of the regex right here? There should be a way
90
+#            to avoid slow operations.
54
 def get_token_from_filepath(filepath):
91
 def get_token_from_filepath(filepath):
55
     token_regex = re.compile(os.path.abspath(os.path.join(Settings.sessions.directory, Settings.sessions.file_template % '(?P<token>.*)')))
92
     token_regex = re.compile(os.path.abspath(os.path.join(Settings.sessions.directory, Settings.sessions.file_template % '(?P<token>.*)')))
56
     token_search_result = token_regex.match(filepath)
93
     token_search_result = token_regex.match(filepath)
59
     return None
96
     return None
60
 
97
 
61
 
98
 
62
-## @brief returns the session's last modification timestamp
99
+##
100
+# @brief Returns the session's last modification timestamp
101
+#
63
 # @param token str
102
 # @param token str
64
 # @return float
103
 # @return float
65
-# @throw ValueError if the given token doesn't match with an existing session
104
+# @raise ValueError if the given token doesn't match with an existing session
105
+#
106
+# @remarks Consider renaming
107
+# @warning Linear search in array, again. See @ref generate_token().
66
 def get_session_last_modified(token):
108
 def get_session_last_modified(token):
67
     if token in __sessions[token]:
109
     if token in __sessions[token]:
68
         return os.stat(__sessions[token]).st_mtime
110
         return os.stat(__sessions[token]).st_mtime
70
         raise ValueError("The given token %s doesn't match with an existing session")
112
         raise ValueError("The given token %s doesn't match with an existing session")
71
 
113
 
72
 
114
 
73
-## @brief returns the token of a new session
74
-# @return str
115
+##
116
+# @brief Starts a new session and returns a new token
117
+#
118
+# @return str : the new token
75
 def start_session():
119
 def start_session():
76
     session = FileSystemSession(generate_token())
120
     session = FileSystemSession(generate_token())
77
     session.path = generate_file_path(session.token)
121
     session.path = generate_file_path(session.token)
122
+    
78
     with open(session.path, 'wb') as session_file:
123
     with open(session.path, 'wb') as session_file:
79
         pickle.dump(session, session_file)
124
         pickle.dump(session, session_file)
125
+
80
     __sessions[session.token] = session.path
126
     __sessions[session.token] = session.path
81
     logger.debug("New session created")
127
     logger.debug("New session created")
128
+
82
     return session.token
129
     return session.token
83
 
130
 
84
 
131
 
85
-## @brief destroys a session given its token
132
+##
133
+# @brief destroys a session given its token
134
+#
86
 # @param token str
135
 # @param token str
87
 def destroy_session(token):
136
 def destroy_session(token):
88
     check_token(token)
137
     check_token(token)
93
     logger.debug("Session %s unregistered" % token)
142
     logger.debug("Session %s unregistered" % token)
94
 
143
 
95
 
144
 
96
-## @brief restores a session's content
145
+##
146
+# @brief Restores a session's content
147
+#
97
 # @param token str
148
 # @param token str
98
 # @return FileSystemSession|None
149
 # @return FileSystemSession|None
99
 def restore_session(token):
150
 def restore_session(token):
128
 
179
 
129
 
180
 
130
 ## @brief session store's garbage collector
181
 ## @brief session store's garbage collector
182
+#
183
+# @remarks 
131
 def gc():
184
 def gc():
132
     # Unregistered files in the session directory
185
     # Unregistered files in the session directory
133
     session_files_directory = os.path.abspath(Settings.sessions.directory)
186
     session_files_directory = os.path.abspath(Settings.sessions.directory)
164
     return session[key]
217
     return session[key]
165
 
218
 
166
 ##
219
 ##
220
+# @brief deletes a session value
221
+#
167
 # @param token str
222
 # @param token str
168
 # @param key str
223
 # @param key str
224
+#
225
+# @todo Should we add a save_session at the end of this method?
169
 def del_session_value(token, key):
226
 def del_session_value(token, key):
170
     session = restore_session(token)
227
     session = restore_session(token)
171
     if key in session:
228
     if key in session:

Loading…
Cancel
Save