|
|
|
@@ -1,13 +1,19 @@ |
|
|
|
import web |
|
|
|
from views.forms import login_form |
|
|
|
import models.session |
|
|
|
import models.user |
|
|
|
from views.utils import get_nav_bar |
|
|
|
import os, hmac, base64, pickle |
|
|
|
import random |
|
|
|
import string |
|
|
|
import hashlib |
|
|
|
import time |
|
|
|
|
|
|
|
# Get html templates |
|
|
|
render = web.template.render('templates/') |
|
|
|
|
|
|
|
# The remember cookie should be valid for a week |
|
|
|
remember_timeout = 3600*24*7 |
|
|
|
|
|
|
|
|
|
|
|
class Login(): |
|
|
|
|
|
|
|
@@ -56,51 +62,42 @@ class Login(): |
|
|
|
session.username = username |
|
|
|
session.userid = userid |
|
|
|
if remember: |
|
|
|
rememberme = self.rememberme() |
|
|
|
web.setcookie('remember', rememberme , 300000000) |
|
|
|
rememberme = self.rememberme(remember_timeout) |
|
|
|
path = web.ctx.homepath + "/" |
|
|
|
web.ctx.headers.append(('Set-Cookie', f'remember={rememberme}; Max-Age={remember_timeout}; Path={path}; Secure; HttpOnly; SameSite=Strict')) |
|
|
|
|
|
|
|
def check_rememberme(self): |
|
|
|
""" |
|
|
|
Validate the rememberme cookie and log in |
|
|
|
""" |
|
|
|
username = "" |
|
|
|
sign = "" |
|
|
|
userid = None |
|
|
|
# If the user selected 'remember me' they log in automatically |
|
|
|
try: |
|
|
|
# Fetch the users cookies if it exists |
|
|
|
cookies = web.cookies() |
|
|
|
# Fetch the remember cookie and convert from string to bytes |
|
|
|
remember_hash = bytes(cookies.remember[2:][:-1], 'ascii') |
|
|
|
# Decode the hash |
|
|
|
decode = base64.b64decode(remember_hash) |
|
|
|
# Load the decoded hash to receive the host signature and the username |
|
|
|
username, sign = pickle.loads(decode) |
|
|
|
except AttributeError as e: |
|
|
|
remember_token = cookies.remember |
|
|
|
userid, expiry = models.session.get_cookie(remember_token) |
|
|
|
except AttributeError: |
|
|
|
# The user did not have the stored remember me cookie |
|
|
|
pass |
|
|
|
|
|
|
|
# If the users signed cookie matches the host signature then log in |
|
|
|
if self.sign_username(username) == sign: |
|
|
|
userid = models.user.get_user_id_by_name(username) |
|
|
|
if userid is not None and expiry > time.time(): |
|
|
|
username = models.user.get_user_name_by_id(userid) |
|
|
|
self.login(username, userid, False) |
|
|
|
|
|
|
|
def rememberme(self): |
|
|
|
def rememberme(self, timeout): |
|
|
|
""" |
|
|
|
Encode a base64 object consisting of the username signed with the |
|
|
|
host secret key and the username. Can be reassembled with the |
|
|
|
hosts secret key to validate user. |
|
|
|
:return: base64 object consisting of signed username and username |
|
|
|
Generate a random token for the user, and store it in the database. |
|
|
|
""" |
|
|
|
session = web.ctx.session |
|
|
|
creds = [ session.username, self.sign_username(session.username) ] |
|
|
|
return base64.b64encode(pickle.dumps(creds)) |
|
|
|
alphabet = string.ascii_uppercase + string.digits |
|
|
|
|
|
|
|
@classmethod |
|
|
|
def sign_username(self, username): |
|
|
|
""" |
|
|
|
Sign the current users name with the hosts secret key |
|
|
|
:return: The users signed name |
|
|
|
""" |
|
|
|
secret = base64.b64decode(self.secret) |
|
|
|
return hmac.HMAC(secret, username.encode('ascii')).hexdigest() |
|
|
|
while True: |
|
|
|
token = ''.join(random.SystemRandom().choice(alphabet) for _ in range(20)) |
|
|
|
if models.session.get_cookie(token)[0] is None: |
|
|
|
break |
|
|
|
|
|
|
|
models.session.set_cookie(session.userid, token, int(time.time() + timeout)) |
|
|
|
return token |