'''Main program''' import socket import sqlite3 from hashlib import sha256 import datetime import random import string import re from UserClasses.user import User from UserClasses.mail import Mail SET = [char for char in string.printable if char not in string.whitespace] USERNAME = '^[a-zA-Z0-9]{8,16}$' PASSWORD = '^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}' class Setup(): '''Setup class that holds all the functions for the main program''' connnected = True current_user = 0 current_quiz = [] username_check = '''SELECT COUNT(1) FROM UserDetails WHERE username = (?);''' date = 0 def __init__(self): '''Constructor to intialise internet connection''' self.connected = self.connect() self.create_dbs() now = datetime.datetime.now() self.date = '-'.join((now.strftime('%Y'), now.strftime('%m'), now.strftime('%d'))) @staticmethod def create_dbs(): '''Create the databases''' user_table_creator = '''CREATE TABLE IF NOT EXISTS `UserDetails` ( `Username` VARCHAR(12) NOT NULL, `Email` VARCHAR(30) NOT NULL, `Salt` VARCHAR(10) NOT NULL, `Hash` VARCHAR(256) NOT NULL, `Date` DATE NOT NULL, PRIMARY KEY (`Username`) );''' connection = sqlite3.connect("UserDatabase.db") cursor = connection.cursor() cursor.execute(user_table_creator) connection.commit() connection.close() quiz_table_creator = '''CREATE TABLE IF NOT EXISTS `QuizDetails` ( `Username` VARCHAR(12) NOT NULL, `Date` DATE NOT NULL, `Questions` VARCHAR(400) NOT NULL, `Score` VARCHAR(256) NOT NULL, `Time` INT(64) NOT NULL );''' connection = sqlite3.connect("QuizDatabase.db") cursor = connection.cursor() cursor.execute(quiz_table_creator) connection.commit() connection.close() @staticmethod def connect() -> str: '''Check whether the user is connected to the internet''' ip_address = socket.gethostbyname(socket.gethostname()) return ip_address == '127.0.0.1' def user_login(self, data: list) -> str: '''Take data from GUI and log the user in if the password is correct''' responses = ['Incorrect password', f'{data[0]} successfully logged in', 'User does not exist'] result = 2 connection = sqlite3.connect("UserDatabase.db") cursor = connection.cursor() cursor.execute(self.username_check, (data[0],)) count = cursor.fetchall()[0][0] if count == 1: result = self.check_password(cursor, data) connection.commit() connection.close() if result == 1: self.current_user = User(data[0]) return responses[result] @staticmethod def check_password(cursor: sqlite3.Cursor, data: list) -> bool: '''Check if entered and stored passwords are equal''' password_check = '''SELECT Hash, Salt FROM UserDetails WHERE Username = (?);''' cursor.execute(password_check, (data[0],)) hashed, salt = cursor.fetchall()[0] new_hashed = Setup.encrypt(data[1], salt) return new_hashed == hashed @staticmethod def encrypt(password: str, salt: str) -> str: '''Encrypts entered password''' return sha256((password + salt).encode('utf-8')).hexdigest() def user_register(self, data: list): '''Register a new user''' responses = ['Passwords are not equal', f'{data[0]} succesfully added to the database', f'{data[0]} already exists', 'Username does not meet requirements', 'Password does not meet requirements'] result = 2 connection = sqlite3.connect("UserDatabase.db") cursor = connection.cursor() cursor.execute(self.username_check, (data[0],)) count = cursor.fetchall()[0][0] if count == 1: result = 2 else: result = self.add_user(cursor, data) connection.commit() connection.close() if result == 1: self.current_user = User(data[0]) return responses[result] @staticmethod def add_user(cursor: sqlite3.Cursor, data: list) -> int: '''Add new user to the database''' if data[2] != data[3]: return 0 if not Setup.validation(USERNAME, data[0]): return 3 if not Setup.validation(PASSWORD, data[2]): return 4 else: salt = ''.join(random.choice(SET) for i in range(16)) user_add = '''INSERT INTO UserDetails VALUES (?, ?, ?, ?, ?);''' cursor.execute(user_add, (data[0], data[1], salt, Setup.encrypt(data[2], salt), Setup.date)) return 1 @staticmethod def validation(regex: str, value: str) -> bool: '''Check for regex match''' match = re.search(regex, value) return match and match.group() == value def reset_password(self, data: list) -> str: '''Reset the users password''' connection = sqlite3.connect("UserDatabase.db") cursor = connection.cursor() if not self.check_password(cursor, data): return "Previous password is incorrect" user_data = list(self.get_user_data(cursor, data)) self.update_password(cursor, user_data, data[2]) connection.commit() connection.close() return 'Reset' @staticmethod def get_user_data(cursor: sqlite3.Cursor, data: list) -> list: get = '''SELECT * FROM UserDetails WHERE Username = (?);''' cursor.execute(get, (data[0],)) return cursor.fetchall()[0] @staticmethod def update_password(cursor: sqlite3.Cursor, user_data: list, new_password: str): '''Update the password in the database''' update = '''UPDATE UserDetails SET Hash = ? WHERE Username = \'''' + user_data[0]+'\';' user_data[3] = Setup.encrypt(new_password, user_data[2]) print(user_data[3]) cursor.execute(update, (user_data[3],)) @staticmethod def write_email(address: str): '''Email confirmation to user''' email = Mail() email.text = 'Your email has been updated succesfuly.' email.set_credentials(address, 'Password reset confirmation') email.email_person(address)