No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.py 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. # -*- coding: utf-8 -*-
  2. import binascii
  3. import datetime
  4. import os
  5. import pickle
  6. import re
  7. import time
  8. from lodel.context import LodelContext
  9. LodelContext.expose_modules(globals(), {
  10. 'lodel.logger': 'logger',
  11. 'lodel.auth.exceptions': ['ClientAuthenticationFailure'],
  12. 'lodel.settings': ['Settings']})
  13. from .filesystem_session import FileSystemSession
  14. __sessions = dict()
  15. SESSION_TOKENSIZE = 150
  16. ## @brief generates a new session token
  17. # @return str
  18. def generate_token():
  19. token = binascii.hexlify(os.urandom(SESSION_TOKENSIZE//2))
  20. if token in __sessions.keys():
  21. token = generate_token()
  22. return token.decode('utf-8')
  23. ## @brief checks the validity of a given session token
  24. # @param token str
  25. # @raise ClientAuthenticationFailure for invalid or not found session token
  26. def check_token(token):
  27. if len(token) != SESSION_TOKENSIZE:
  28. raise ClientAuthenticationFailure("Invalid token string")
  29. if token not in __sessions.keys():
  30. raise ClientAuthenticationFailure("No session found for this token")
  31. ## @brief returns a session file path for a specific token
  32. def generate_file_path(token):
  33. return os.path.abspath(os.path.join(Settings.sessions.directory, Settings.sessions.file_template) % token)
  34. def get_token_from_filepath(filepath):
  35. token_regex = re.compile(os.path.abspath(os.path.join(Settings.sessions.directory, Settings.sessions.file_template % '(?P<token>.*)')))
  36. token_search_result = token_regex.match(filepath)
  37. if token_search_result is not None:
  38. return token_search_result.groupdict()['token']
  39. return None
  40. ## @brief returns the session's last modification timestamp
  41. # @param token str
  42. # @return float
  43. # @raise ValueError if the given token doesn't match with an existing session
  44. def get_session_last_modified(token):
  45. if token in __sessions[token]:
  46. return os.stat(__sessions[token]).st_mtime
  47. else:
  48. raise ValueError("The given token %s doesn't match with an existing session")
  49. ## @brief returns the token of a new session
  50. # @return str
  51. def start_session():
  52. session = FileSystemSession(generate_token())
  53. session.path = generate_file_path(session.token)
  54. with open(session.path, 'wb') as session_file:
  55. pickle.dump(session, session_file)
  56. __sessions[session.token] = session.path
  57. logger.debug("New session created")
  58. return session.token
  59. ## @brief destroys a session given its token
  60. # @param token str
  61. def destroy_session(token):
  62. check_token(token)
  63. if os.path.isfile(__sessions[token]):
  64. os.unlink(__sessions[token])
  65. logger.debug("Session file for %s destroyed" % token)
  66. del(__sessions[token])
  67. logger.debug("Session %s unregistered" % token)
  68. ## @brief restores a session's content
  69. # @param token str
  70. # @return FileSystemSession|None
  71. def restore_session(token):
  72. gc()
  73. check_token(token)
  74. logger.debug("Restoring session : %s" % token)
  75. if os.path.isfile(__sessions[token]):
  76. with open(__sessions[token], 'rb') as session_file:
  77. session = pickle.load(session_file)
  78. return session
  79. else:
  80. return None # raise FileNotFoundError("Session file not found for the token %s" % token)
  81. ## @brief saves the session's content to a file
  82. # @param token str
  83. # @param datas dict
  84. def save_session(token, datas):
  85. session = datas
  86. if not isinstance(datas, FileSystemSession):
  87. session = FileSystemSession(token)
  88. session.path = generate_file_path(token)
  89. session.update(datas)
  90. with open(__sessions[token], 'wb') as session_file:
  91. pickle.dump(session, session_file)
  92. if token not in __sessions.keys():
  93. __sessions[token] = session.path
  94. logger.debug("Session %s saved" % token)
  95. ## @brief session store's garbage collector
  96. def gc():
  97. # Unregistered files in the session directory
  98. session_files_directory = os.path.abspath(Settings.sessions.directory)
  99. for session_file in [file_path for file_path in os.listdir(session_files_directory) if os.path.isfile(os.path.join(session_files_directory, file_path))]:
  100. session_file_path = os.path.join(session_files_directory, session_file)
  101. token = get_token_from_filepath(session_file_path)
  102. if token is None or token not in __sessions.keys():
  103. os.unlink(session_file_path)
  104. logger.debug("Unregistered session file %s has been deleted" % session_file)
  105. # Expired registered sessions
  106. for token in __sessions.keys():
  107. if os.path.isfile(__sessions[token]):
  108. now_timestamp = time.mktime(datetime.datetime.now().timetuple())
  109. if now_timestamp - get_session_last_modified(token) > Settings.sessions.expiration:
  110. destroy_session(token)
  111. logger.debug("Expired session %s has been destroyed" % token)
  112. def set_session_value(token, key, value):
  113. session = restore_session(token)
  114. session[key] = value
  115. save_session(token, session)
  116. def get_session_value(token, key):
  117. session = restore_session(token)
  118. return session[key]
  119. def del_session_value(token, key):
  120. session = restore_session(token)
  121. if key in session:
  122. del(session[key])