Matrices-Practice-Tool / src / Setup / setup.py
setup.py
Raw
'''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)