main.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import configparser
  2. import lmdb
  3. import cherrypy
  4. import pickle
  5. import chevron
  6. from hashlib import sha256
  7. from logger import Logger
  8. # main.py will run golestan_reporter and any other services
  9. from golestan_reporter import GolestanReporter
  10. import os
  11. T = 'main'
  12. CONFIG_FILE_DIR = 'config.ini'
  13. CONFIG_FILE_ENCODER = 'utf8'
  14. DEBUG = True
  15. DEV_PASS = 'eda57e1df3f6fb8a9ac094b95fc9cfb20d4783db8ecc8261f232f606fe35cbe3' # hint: adamsmozi
  16. class TemplatesCache:
  17. def __init__(self, templates_dir, cache):
  18. self.cache = cache
  19. get_path = lambda x: os.path.join(templates_dir, x)
  20. self.__templates = {
  21. 'signin' : get_path('signin.html'),
  22. 'signup' : get_path('signup.html')
  23. }
  24. if cache:
  25. for k, v in self.__templates:
  26. with open(v) as f:
  27. self.__templates[k]=f.read()
  28. def get_template(self, template_key):
  29. if self.cache:
  30. return self.__templates[template_key]
  31. else:
  32. with open(self.__templates[template_key]) as template_file:
  33. template = template_file.read()
  34. return template
  35. @cherrypy.tools.register('before_handler')
  36. def auth(class_):
  37. s = cherrypy.session
  38. if class_=='all' and s.get('user class') is not None:
  39. return
  40. elif s.get('user class') in class_:
  41. return
  42. else:
  43. raise cherrypy.HTTPRedirect('/signin')
  44. class Root:
  45. def __init__(self, env, users_db, config: configparser.SectionProxy, logger: Logger, templates):
  46. self.templates = templates
  47. self.env = env
  48. self.usersDB = users_db
  49. self.cfg = config
  50. self.l = logger
  51. self.get_hashsum = lambda x: sha256(x.encode()).hexdigest()
  52. def get_user_data(self, user, key = None):
  53. self.l.d(f'getting user({user}) info',T)
  54. try:
  55. with self.env.begin(self.usersDB) as txn:
  56. data = txn.get(user.enconde())
  57. user_info = pickle.loads(data)
  58. if key:
  59. return user_info[key]
  60. return user_info
  61. except Exception as e:
  62. self.l.e('error on getting user info',T)
  63. self.l.d(f'{type(e)}: {e}',T)
  64. def set_user_data(self, user, value, key=None):
  65. self.l.i(f'setting user({user}) info',T)
  66. self.l.d(f'key:{key}'+', value:{value}'if key else ', value is full user info',T)
  67. try:
  68. if key:
  69. value_ = value
  70. value = self.get_user_data(user)
  71. value[key] = value_
  72. data = pickle.dumps(value)
  73. with self.env.begin(self.usersDB,write=True) as txn:
  74. txn.put(key.enconde(), data)
  75. except Exception as e:
  76. self.l.e('error on setting user info',T)
  77. self.l.d(f'{type(e)}: {e}',T)
  78. @cherrypy.expose
  79. def signup(self, **info):
  80. pass
  81. @cherrypy.expose
  82. def verify(self, q):
  83. pass
  84. @cherrypy.expose
  85. def signin(self, username=None, password=None):
  86. if username is None or password is None:
  87. # signin form
  88. return self.templates.get_template('signin')
  89. else:
  90. # do signin:
  91. if username == 'admin':
  92. if self.get_hashsum(password)==self.cfg['admin_pass_sha256']:
  93. cherrypy.session['user class']='admin'
  94. cherrypy.session['login']=True
  95. raise cherrypy.HTTPRedirect('/admincp')
  96. else:
  97. return 'incorrect password'
  98. elif username == 'developer' and DEBUG:
  99. if self.get_hashsum(password)==DEV_PASS:
  100. cherrypy.session['user class']='dev'
  101. cherrypy.session['login']=True
  102. raise cherrypy.HTTPRedirect('/devtool')
  103. # TODO: add devtool
  104. else:
  105. return 'incorrect password'
  106. else:
  107. user_info = self.get_user_data(username)
  108. if user_info:
  109. if self.get_hashsum(password) == user_info['passhash']:
  110. cherrypy.session['user class'] = 'user'
  111. cherrypy.session['username'] = username
  112. cherrypy.session['login']=True
  113. raise cherrypy.HTTPRedirect('/cp')
  114. else:
  115. return 'incorrect password'
  116. else:
  117. return 'incorrect username'
  118. @cherrypy.expose
  119. def index(self):
  120. # no index page at now. this will redirect user to signin
  121. s = cherrypy.session
  122. if s.get('user class') == 'admin':
  123. raise cherrypy.HTTPRedirect('/admincp')
  124. elif s.get('user class') == 'dev' and DEBUG:
  125. raise cherrypy.HTTPRedirect('/devtool')
  126. elif s.get('user class') == 'user':
  127. raise cherrypy.HTTPRedirect('/cp')
  128. else:
  129. raise cherrypy.HTTPRedirect('/signin')
  130. @cherrypy.auth(('dev','users'))
  131. def cp(self):
  132. s = cherrypy.session
  133. student = None
  134. if s.get('user class') == 'user':
  135. if s.get('user') != None:
  136. student = self.get_user_data(s.get('user'))
  137. else:
  138. self.l.w('user class is user but no user attribute found in session',T)
  139. raise cherrypy.HTTPRedirect('/signin')
  140. # TODO: add web interface
  141. @cherrypy.auth(('dev','admin'))
  142. def admincp(self):
  143. # TODO: add web interface
  144. pass
  145. cfg = configparser.ConfigParser()
  146. # TODO: use a dynamic cfg directory given in arg
  147. with open(CONFIG_FILE_DIR, encoding=CONFIG_FILE_ENCODER) as cfgFile:
  148. cfg.readfp(cfgFile)
  149. maincfg=cfg['Main']
  150. logger = Logger(maincfg.get('log_dir','.log'), maincfg.getint('log_level',0), DEBUG)
  151. templates = TemplatesCache(maincfg.get('templates_dir'),not DEBUG)
  152. with lmdb.open(maincfg.get('db_dir','.db'), max_dbs=2) as env:
  153. usersDB = env.open_db(maincfg.get('users_database','users').encode())
  154. golestan_reporter = GolestanReporter(env=env, users_db=usersDB, config=cfg['Golestan reporter'], logger=logger, tempaltes=templates)
  155. # web services:
  156. root = Root(env, usersDB, maincfg, logger, templates)
  157. golestan_reporter.start()
  158. # TODO: run web tools
  159. cherry_cfg = {
  160. "global":
  161. {
  162. "server.socket_host": maincfg.get('host','0.0.0.0'),
  163. "server.socket_port": maincfg.getint('port',8080),
  164. "server.socket_file": maincfg.get('unix_socket'),
  165. "tools.sessions.on": True,
  166. "tools.staticdir.on": True,
  167. "tools.staticdir.dir": os.path.abspath("./webInterface/files/"),
  168. "tools.staticdir.root": "/",
  169. "environment": None if DEBUG else "production"
  170. }
  171. }
  172. cherrypy.quickstart(root, '/', cherry_cfg)
  173. golestan_reporter.join()