import enum import random import unicodedata import sqlite3 from passlib.hash import argon2 class userstatus(enum.Enum): # These will be stored in the database, be mindful of not changing the numbers deleted = 0 normal = 1 admin = 2 csprng = random.SystemRandom() def add_user(userdb, *, username, password, email, parent, status): """Add a user to the database""" global csprgn assert type(username) == str assert type(password) == str assert type(email) == str assert type(parent) == int or parent is None assert status in userstatus # Generate a user ID. SQLite uses 64 bit signed ints, so generate at max 2⁶³-1 userid = csprng.randrange(2**63) # First unicode normalize the password, then hash it with argon2 password = unicodedata.normalize('NFKC', password) password = argon2.hash(password) # Convert status into an int for storage status = status.value # Add the user into the database cursor = userdb.cursor() cursor.execute('INSERT INTO users VALUES (?, ?, ?, ?, ?, ?, ?);', (userid, parent, status, password, username, email, '')) userdb.commit() def initialize_userdb(userdb, admin_user, admin_password): """Creates a bare-bones user database with only admin This should never be run outside of the initialization script""" cursor = userdb.cursor() cursor.execute('''CREATE TABLE users ( id integer NOT NULL PRIMARY KEY, parent integer, status integer NOT NULL, password text NOT NULL, username text NOT NULL, email text NOT NULL, comment text NOT NULL );''') userdb.commit() add_user(userdb, username = admin_user, password = admin_password, email = '', parent = None, status = userstatus.admin)