Commit 27e15117341fa400572d0fca9bf9f74dc3094efb
1 parent
785ca6d2
Exists in
master
and in
1 other branch
- 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
app.py
| @@ -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 |
serve.py
| @@ -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 |