diff --git a/database.py b/database.py index 98843ab..341b1d8 100644 --- a/database.py +++ b/database.py @@ -3,10 +3,14 @@ import random import unicodedata import sqlite3 +from collections import namedtuple + from passlib.hash import argon2 import config +UserInfo = namedtuple('UserInfo', ('id', 'parent', 'status', 'username', 'email', 'comment')) + # ------------------------------------------------------------------ # General # ------------------------------------------------------------------ @@ -29,6 +33,7 @@ def connect(): # ------------------------------------------------------------------ def add_user(db, *, username, password, email, parent, status): + # TODO: Ensure users are unique """Add a user to the database Will not commit the changes itself, so run .commit() on the database object yourself""" global csprgn @@ -57,6 +62,65 @@ def add_user(db, *, username, password, email, parent, status): cursor.execute('PRAGMA foreign_keys = ON;') # Fail if we insert a user with bogus parent field cursor.execute('INSERT INTO users VALUES (?, ?, ?, ?, ?, ?, ?);', (userid, parent, status, password, username, email, '')) +def get_userid(db, username): + """Returns the user ID associated with given username + If no user was found, returns None""" + # Unicode normalize the username + username = unicodedata.normalize('NFKC', username) + + # Get the user ID + cursor = db.cursor() + cursor.execute('SELECT id FROM users WHERE username = ?', (username,)) + results = cursor.fetchall() + + # If no user was found, return None + if len(results) != 1: + return None + + return results[0][0] + +def check_password(db, userid, password): + """Checks the password for given userid + Will return True if the password matches and False otherwise""" + # Unicode normalize the password + password = unicodedata.normalize('NFKC', password) + + # Get the password and status + cursor = db.cursor() + cursor.execute('SELECT password, status FROM users WHERE id = ?', (userid,)) + results = cursor.fetchall() + + # If no user of that name, fail + if len(results) != 1: + return False + + hashed, status = results[0] + + # If user has been deleted, fail + if status == userstatus.deleted: + return False + + # Check the password + return argon2.verify(password, hashed) + +def get_user_info(db, userid): + """Returns a UserInfo object representing the data associated with a user + If no user was found, returns None""" + cursor = db.cursor() + cursor.execute('SELECT id, parent, status, username, email, comment FROM users WHERE id = ?', (userid,)) + results = cursor.fetchall() + + # If no user was found, return None + if len(results) != 1: + return None + + userid, parent, status, username, email, comment = results[0] + + # Translate status into enum + status = userstatus(status) + + return UserInfo(userid, parent, status, username, email, comment) + def initialize_users(db, admin_user, admin_password): """Creates a bare-bones user table with only admin user This should never be run outside of the initialization script""" diff --git a/generate_html.py b/generate_html.py index 774a3af..4456cac 100644 --- a/generate_html.py +++ b/generate_html.py @@ -90,6 +90,31 @@ def index(): soup = new_soup() return page_skeleton(page_title = config.site_name, contents = [], soup = soup) +def login_forward(raw_path): + """Returns html + Creates a page telling the user to log in""" + # TODO: Take the user back to where they were + soup = new_soup() + + # TODO: Don't hardcode + contents = bs4.BeautifulSoup(''' +

Login to access

+
+
+ +
+
+ +
+
+ +
+
+ ''') + + # TODO: Internationalization + return page_skeleton(page_title = 'Login to ' + config.site_name, contents = contents, soup = soup) + def error_404(path): """Returns html""" soup = new_soup() diff --git a/server.py b/server.py index b1c8753..c1c17a3 100644 --- a/server.py +++ b/server.py @@ -7,7 +7,9 @@ import generate_html class HTTPRequestHandler(http.server.BaseHTTPRequestHandler): server_version = 'Buranun/0.0' - protocol_version = 'HTTP/1.1' + # TODO: Look into keepalive problems in links2 + #protocol_version = 'HTTP/1.1' + protocol_version = 'HTTP/1.0' def __send_html(self, html, *, status_code = 200): encoded = html.encode('utf-8') @@ -54,7 +56,13 @@ class HTTPRequestHandler(http.server.BaseHTTPRequestHandler): print(received_cookies['buranun_session'].value) else: - print('no cookies') + # Display page that tells user to login + # TODO: Have it forward the user back to the page where they were at + html = generate_html.login_forward(self.path) + self.__send_html(html) + + # Don't run rest of the function + return path = urllib.parse.unquote(self.path)