Commit 27e15117341fa400572d0fca9bf9f74dc3094efb

Authored by Miguel Barão
1 parent 785ca6d2
Exists in master and in 1 other branch dev

- login is now async on the bcrypt function that checks the password.

Showing 2 changed files with 18 additions and 13 deletions   Show diff stats
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 from os import path 3 from os import path
4 import logging 4 import logging
5 from contextlib import contextmanager # `with` statement in db sessions 5 from contextlib import contextmanager # `with` statement in db sessions
  6 +import asyncio
6 7
7 # user installed packages 8 # user installed packages
8 import bcrypt 9 import bcrypt
@@ -23,8 +24,11 @@ class AppException(Exception): @@ -23,8 +24,11 @@ class AppException(Exception):
23 # ============================================================================ 24 # ============================================================================
24 # helper functions 25 # helper functions
25 # ============================================================================ 26 # ============================================================================
26 -def check_password(try_pw, password):  
27 - return password == bcrypt.hashpw(try_pw.encode('utf-8'), password) 27 +async def check_password(try_pw, password):
  28 + try_pw = try_pw.encode('utf-8')
  29 + loop = asyncio.get_event_loop()
  30 + hashed_pw = await loop.run_in_executor(None, bcrypt.hashpw, try_pw, password)
  31 + return password == hashed_pw
28 32
29 # ============================================================================ 33 # ============================================================================
30 # Application 34 # Application
@@ -69,7 +73,6 @@ class App(object): @@ -69,7 +73,6 @@ class App(object):
69 # connect to database and check registered students 73 # connect to database and check registered students
70 dbfile = path.expanduser(self.testfactory['database']) 74 dbfile = path.expanduser(self.testfactory['database'])
71 engine = create_engine(f'sqlite:///{dbfile}', echo=False) 75 engine = create_engine(f'sqlite:///{dbfile}', echo=False)
72 - # self.Session = scoped_session(sessionmaker(bind=engine)) # FIXME not scoped in tornado  
73 self.Session = sessionmaker(bind=engine) 76 self.Session = sessionmaker(bind=engine)
74 77
75 try: 78 try:
@@ -95,7 +98,7 @@ class App(object): @@ -95,7 +98,7 @@ class App(object):
95 logger.critical('----------- !!! Server terminated !!! -----------') 98 logger.critical('----------- !!! Server terminated !!! -----------')
96 99
97 # ----------------------------------------------------------------------- 100 # -----------------------------------------------------------------------
98 - def login(self, uid, try_pw): 101 + async def login(self, uid, try_pw):
99 if uid.startswith('l'): # remove prefix 'l' 102 if uid.startswith('l'): # remove prefix 'l'
100 uid = uid[1:] 103 uid = uid[1:]
101 104
@@ -112,7 +115,7 @@ class App(object): @@ -112,7 +115,7 @@ class App(object):
112 self.update_student_password(uid, try_pw) 115 self.update_student_password(uid, try_pw)
113 pw_ok = True 116 pw_ok = True
114 else: # check password 117 else: # check password
115 - pw_ok = check_password(try_pw, password) 118 + pw_ok = await check_password(try_pw, password) # async bcrypt
116 119
117 if pw_ok: # success 120 if pw_ok: # success
118 self.allowed.discard(uid) # remove from set of allowed students 121 self.allowed.discard(uid) # remove from set of allowed students
@@ -23,6 +23,9 @@ from app import App, AppException @@ -23,6 +23,9 @@ from app import App, AppException
23 from tools import load_yaml, md_to_html 23 from tools import load_yaml, md_to_html
24 24
25 25
  26 +# -------------------------------------------------------------------------
  27 +# Web Application. Routes to handler classes.
  28 +# -------------------------------------------------------------------------
26 class WebApplication(tornado.web.Application): 29 class WebApplication(tornado.web.Application):
27 def __init__(self, testapp, debug=False): 30 def __init__(self, testapp, debug=False):
28 handlers = [ 31 handlers = [
@@ -73,13 +76,10 @@ class LoginHandler(BaseHandler): @@ -73,13 +76,10 @@ class LoginHandler(BaseHandler):
73 self.render('login.html', error='') 76 self.render('login.html', error='')
74 77
75 # async 78 # async
76 - def post(self): 79 + async def post(self):
77 uid = self.get_body_argument('uid') 80 uid = self.get_body_argument('uid')
78 pw = self.get_body_argument('pw') 81 pw = self.get_body_argument('pw')
79 -  
80 - # loop = asyncio.get_event_loop()  
81 - # login_ok = await loop.run_in_executor(None, self.testapp.login, uid, pw)  
82 - login_ok = self.testapp.login(uid, pw) 82 + login_ok = await self.testapp.login(uid, pw)
83 83
84 if login_ok: 84 if login_ok:
85 self.set_secure_cookie("user", str(uid), expires_days=30) 85 self.set_secure_cookie("user", str(uid), expires_days=30)
@@ -151,10 +151,12 @@ class FileHandler(BaseHandler): @@ -151,10 +151,12 @@ class FileHandler(BaseHandler):
151 151
152 152
153 # ------------------------------------------------------------------------- 153 # -------------------------------------------------------------------------
154 -# FIXME images missing, needs testing 154 +# Test shown to students
155 # ------------------------------------------------------------------------- 155 # -------------------------------------------------------------------------
156 class TestHandler(BaseHandler): 156 class TestHandler(BaseHandler):
157 - templates = { 157 + SUPPORTED_METHODS = ['GET', 'POST']
  158 +
  159 + _templates = {
158 'radio': 'question-radio.html', 160 'radio': 'question-radio.html',
159 'checkbox': 'question-checkbox.html', 161 'checkbox': 'question-checkbox.html',
160 'text': 'question-text.html', 162 'text': 'question-text.html',
@@ -175,7 +177,7 @@ class TestHandler(BaseHandler): @@ -175,7 +177,7 @@ class TestHandler(BaseHandler):
175 def get(self): 177 def get(self):
176 uid = self.current_user 178 uid = self.current_user
177 t = self.testapp.get_student_test(uid) or self.testapp.generate_test(uid) 179 t = self.testapp.get_student_test(uid) or self.testapp.generate_test(uid)
178 - self.render('test.html', t=t, md=md_to_html, templ=self.templates) 180 + self.render('test.html', t=t, md=md_to_html, templ=self._templates)
179 181
180 # POST 182 # POST
181 @tornado.web.authenticated 183 @tornado.web.authenticated