Enforce uniqueness of users and move initialize_* to initialize.py
This commit is contained in:
parent
e2cc012c30
commit
fb9b6ba258
81
database.py
81
database.py
|
@ -1,5 +1,6 @@
|
||||||
import enum
|
import enum
|
||||||
import random
|
import random
|
||||||
|
import threading
|
||||||
import unicodedata
|
import unicodedata
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
|
@ -32,10 +33,12 @@ def connect():
|
||||||
# Users
|
# Users
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
user_modify_lock = threading.Lock()
|
||||||
|
|
||||||
def add_user(db, *, username, password, email, parent, status):
|
def add_user(db, *, username, password, email, parent, status):
|
||||||
# TODO: Ensure users are unique
|
|
||||||
"""Add a user to the database
|
"""Add a user to the database
|
||||||
Will not commit the changes itself, so run .commit() on the database object yourself"""
|
Returns True is user was added succesfully and False if username was already in use
|
||||||
|
Will not commit the changes itself, so run .commit() on the database object yourself."""
|
||||||
global csprgn
|
global csprgn
|
||||||
|
|
||||||
assert type(username) == str
|
assert type(username) == str
|
||||||
|
@ -44,9 +47,6 @@ def add_user(db, *, username, password, email, parent, status):
|
||||||
assert type(parent) == int or parent is None
|
assert type(parent) == int or parent is None
|
||||||
assert status in userstatus
|
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)
|
|
||||||
|
|
||||||
# Unicode normalize the username
|
# Unicode normalize the username
|
||||||
username = unicodedata.normalize('NFKC', username)
|
username = unicodedata.normalize('NFKC', username)
|
||||||
|
|
||||||
|
@ -57,11 +57,35 @@ def add_user(db, *, username, password, email, parent, status):
|
||||||
# Convert status into an int for storage
|
# Convert status into an int for storage
|
||||||
status = status.value
|
status = status.value
|
||||||
|
|
||||||
# Add the user into the database
|
# We don't want any changes to the database to occur while we check if ID and username are available
|
||||||
|
with user_modify_lock:
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
|
||||||
|
# Check that the username is unique
|
||||||
|
cursor.execute('SELECT id FROM users WHERE username = ?;', (username,))
|
||||||
|
results = cursor.fetchall()
|
||||||
|
|
||||||
|
if len(results) != 0:
|
||||||
|
return False # Username is already in use
|
||||||
|
|
||||||
|
# Generate a user ID
|
||||||
|
while True:
|
||||||
|
# SQLite uses 64 bit signed ints, so generate at max 2⁶³-1
|
||||||
|
userid = csprng.randrange(2**63)
|
||||||
|
|
||||||
|
# Check that the user ID is unique
|
||||||
|
cursor.execute('SELECT id FROM users WHERE id = ?;', (userid,))
|
||||||
|
results = cursor.fetchall()
|
||||||
|
|
||||||
|
if len(results) == 0:
|
||||||
|
break # It is unique
|
||||||
|
|
||||||
|
# Add the user into the database
|
||||||
cursor.execute('PRAGMA foreign_keys = ON;') # Fail if we insert a user with bogus parent field
|
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, ''))
|
cursor.execute('INSERT INTO users VALUES (?, ?, ?, ?, ?, ?, ?);', (userid, parent, status, password, username, email, ''))
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def get_userid(db, username):
|
def get_userid(db, username):
|
||||||
"""Returns the user ID associated with given username
|
"""Returns the user ID associated with given username
|
||||||
If no user was found, returns None"""
|
If no user was found, returns None"""
|
||||||
|
@ -121,32 +145,6 @@ def get_user_info(db, userid):
|
||||||
|
|
||||||
return UserInfo(userid, parent, status, username, email, comment)
|
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"""
|
|
||||||
|
|
||||||
cursor = db.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,
|
|
||||||
|
|
||||||
FOREIGN KEY(parent) REFERENCES users(id)
|
|
||||||
);''')
|
|
||||||
|
|
||||||
add_user(db, username = admin_user, password = admin_password, email = '', parent = None, status = userstatus.admin)
|
|
||||||
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# Boards
|
# Boards
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
@ -159,22 +157,3 @@ def list_boards(db):
|
||||||
|
|
||||||
# The results look like [('foo',), ('bar',), ('baz',)]
|
# The results look like [('foo',), ('bar',), ('baz',)]
|
||||||
return [i[0] for i in results]
|
return [i[0] for i in results]
|
||||||
|
|
||||||
def initialize_boards(db, boards):
|
|
||||||
"""Creates a table of boards
|
|
||||||
This should never be run outside of the initialization script"""
|
|
||||||
|
|
||||||
cursor = db.cursor()
|
|
||||||
|
|
||||||
cursor.execute('''CREATE TABLE boards (
|
|
||||||
id integer NOT NULL PRIMARY KEY,
|
|
||||||
name text NOT NULL
|
|
||||||
);''')
|
|
||||||
|
|
||||||
# .executemany() wants them in the format [("board1",), ("board2",), …]
|
|
||||||
boards = [(board_name,) for board_name in boards]
|
|
||||||
|
|
||||||
# Use NULL to have SQLite generate the IDs automatically
|
|
||||||
cursor.executemany('INSERT INTO boards VALUES (NULL, ?);', boards)
|
|
||||||
|
|
||||||
db.commit()
|
|
||||||
|
|
|
@ -3,12 +3,58 @@ import sqlite3
|
||||||
import config
|
import config
|
||||||
import database
|
import database
|
||||||
|
|
||||||
|
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"""
|
||||||
|
|
||||||
|
cursor = db.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,
|
||||||
|
|
||||||
|
FOREIGN KEY(parent) REFERENCES users(id)
|
||||||
|
);''')
|
||||||
|
|
||||||
|
# Since we just created the database, add_user cannot have conflicting user
|
||||||
|
database.add_user(db, username = admin_user, password = admin_password, email = '', parent = None, status = database.userstatus.admin)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
def initialize_boards(db, boards):
|
||||||
|
"""Creates a table of boards
|
||||||
|
This should never be run outside of the initialization script"""
|
||||||
|
|
||||||
|
cursor = db.cursor()
|
||||||
|
|
||||||
|
cursor.execute('''CREATE TABLE boards (
|
||||||
|
id integer NOT NULL PRIMARY KEY,
|
||||||
|
name text NOT NULL
|
||||||
|
);''')
|
||||||
|
|
||||||
|
# .executemany() wants them in the format [("board1",), ("board2",), …]
|
||||||
|
boards = [(board_name,) for board_name in boards]
|
||||||
|
|
||||||
|
# Use NULL to have SQLite generate the IDs automatically
|
||||||
|
cursor.executemany('INSERT INTO boards VALUES (NULL, ?);', boards)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
config.load('buranun.conf')
|
config.load('buranun.conf')
|
||||||
with database.connect() as db:
|
with database.connect() as db:
|
||||||
username = input('admin username: ')
|
username = input('admin username: ')
|
||||||
password = input('admin password: ')
|
password = input('admin password: ')
|
||||||
database.initialize_users(db, username, password)
|
initialize_users(db, username, password)
|
||||||
|
|
||||||
boards = input('boards: ').split()
|
boards = input('boards: ').split()
|
||||||
database.initialize_boards(db, boards)
|
initialize_boards(db, boards)
|
||||||
|
|
Loading…
Reference in New Issue