diff --git a/goodchain/readme.md b/goodchain/readme.md new file mode 100644 index 0000000..935843e --- /dev/null +++ b/goodchain/readme.md @@ -0,0 +1,16 @@ +# GOODCHAIN +This is the final assesment of the blockchain minor of period 1. [EXPLANATION FILE](https://hrnl-my.sharepoint.com/:w:/g/personal/bashb_hr_nl/Ed7VWyB5vbtPmCgeKl1g_S4BbkmE7CPrS1sigEfSAOdmDw?e=0fDOJQ) + +# INSTALL +1: Install all the packages +``` +pip install -r requirements.txt +``` + +# TODO +- [ ] 1 Create a gui +- [ ] 2 Transfer coins +- [ ] 3 Mine new blocks +- [ ] 4 explore the blockchain + + \ No newline at end of file diff --git a/goodchain/requirements.txt b/goodchain/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/goodchain/src/classes/Signature.py b/goodchain/src/classes/Signature.py new file mode 100644 index 0000000..828db26 --- /dev/null +++ b/goodchain/src/classes/Signature.py @@ -0,0 +1,34 @@ +from cryptography.exceptions import * +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives import serialization + +class Signature: + def generate_keys(): + private_key = rsa.generate_private_key(public_exponent=65537,key_size=2048) + public_key = private_key.public_key() + + return private_key, public_key + + def keys_to_bytes(private_key, public_key): + prv_ser = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption()) + + pbc_ser = public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo) + + return prv_ser, pbc_ser + + def bytes_to_keys(private_ser, public_ser): + private_key = serialization.load_pem_private_key( + private_ser, + password=None + ) + public_key = serialization.load_pem_public_key( + public_ser + ) + return private_key, public_key \ No newline at end of file diff --git a/goodchain/src/classes/User.py b/goodchain/src/classes/User.py new file mode 100644 index 0000000..730d3c3 --- /dev/null +++ b/goodchain/src/classes/User.py @@ -0,0 +1,52 @@ +from getpass import getpass +from classes.Signature import Signature + +class User: + def __init__(self, db, private_key=None, public_key=None, username=None, password=None): + self.db = db + self.private_key = private_key + self.public_key = public_key + self.username = username + self.password = password + + def login(self): + input_username = input("Username: ") + input_password = getpass("Password: ") + + user = self.db.loginUser(input_username, input_password) + + # check if user exists + if user: + private_key, public_key = Signature.bytes_to_keys(user['private_key'], user['public_key']) + self.private_key = private_key + self.public_key = public_key + self.username = user['username'] + return True + return False + + def register(self): + input_username = input("Username: ") + input_password = getpass("Password: ") + + # check if username is already taken + if self.db.fetchUserByUsername(input_username): + return False + + # create sig for user + private_key, public_key = Signature.generate_keys() + private_ser, public_ser = Signature.keys_to_bytes(private_key, public_key) + # register user + if self.db.createUser( private_ser, public_ser, input_username, input_password): + self.private_key = private_key + self.public_key = public_key + self.username = input_username + return True + return False + + def logout(self): + self.db.close() + self.private_key = None + self.public_key = None + self.username = None + self.password = None + return True \ No newline at end of file diff --git a/goodchain/src/goodchain.db b/goodchain/src/goodchain.db new file mode 100644 index 0000000..0525873 Binary files /dev/null and b/goodchain/src/goodchain.db differ diff --git a/goodchain/src/helpers/DatabaseHelper.py b/goodchain/src/helpers/DatabaseHelper.py new file mode 100644 index 0000000..d323ee8 --- /dev/null +++ b/goodchain/src/helpers/DatabaseHelper.py @@ -0,0 +1,93 @@ +import sqlite3 + +class DatabaseHelper: + def __init__(self, db=None): + print("Initializing database") + self.conn = None + self.cursor = None + + if db: + self.open(db) + + def __enter__(self): + return self + + def __exit__(self): + self.close() + + def open(self, db): + try: + self.conn = sqlite3.connect(db) + self.cursor = self.conn.cursor() + except: + pass + + def commit(self): + if self.conn: + self.conn.commit() + + def query(self, sql, values=None): + if values == None: + self.cursor.execute(sql) + self.commit() + else: + self.cursor.execute(sql, values) + self.commit() + + def close(self): + if self.conn: + self.conn.commit() + self.conn.close() + self.cursor.close() + + # Query functions + def loginUser(self, username, password): + if not self.conn: + return None + try: + self.cursor.execute("SELECT * FROM `users` WHERE (`username` = ? AND `password` = ?)", (username, password,)) + return self.cursor.fetchone() + except sqlite3.Error as error: + print(error) + return None + + def createUser(self, private_key, public_key, username, password): + if not self.conn: + return False + try: + self.cursor.execute("INSERT INTO `users` (private_key, public_key, username, password) VALUES (?, ?, ?, ?)", (private_key, public_key, username, password,)) + self.commit() + return True + except sqlite3.Error as error: + print(error) + return False + + def changePasswordUser(self, user_privatekey, password): + if not self.conn: + return None + + try: + self.cursor.execute("UPDATE `users` SET `password` = ? WHERE `private_key` = ?", (password, user_privatekey,)) + self.commit() + + return True + + except sqlite3.Error as error: + print(error) + return None + + def fetchUserByUsername(self, username): + if not self.conn: + return None + + try: + self.cursor.execute("SELECT * FROM `users` WHERE `username` = ?", (username,)) + + return self.cursor.fetchone() + + except sqlite3.Error as error: + print(error) + return None + + def checkMigrations(self): + self.query("CREATE TABLE IF NOT EXISTS `users` ( `private_key` BLOB NOT NULL , `public_key` BLOB NOT NULL , `username` VARCHAR(255) NOT NULL , `password` VARCHAR(255) NOT NULL )") diff --git a/goodchain/src/helpers/LoggerHelper.py b/goodchain/src/helpers/LoggerHelper.py new file mode 100644 index 0000000..f9bca2d --- /dev/null +++ b/goodchain/src/helpers/LoggerHelper.py @@ -0,0 +1 @@ +# Not sure if we're planning to log anything tho \ No newline at end of file diff --git a/goodchain/src/helpers/MenuHelper.py b/goodchain/src/helpers/MenuHelper.py new file mode 100644 index 0000000..5935555 --- /dev/null +++ b/goodchain/src/helpers/MenuHelper.py @@ -0,0 +1,122 @@ +import os + +from classes.User import User + +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKCYAN = '\033[96m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + +class MenuHelper: + def __init__(self, db): + self.db = db + + self.start_menu = {} + self.user_menu = {} + + self.start_menu[0] = "Exit" + self.start_menu[1] = "Explore the Blockchain" + self.start_menu[2] = "Login" + self.start_menu[3] = "Sign up" + + self.user_menu[0] = "Log out" + self.user_menu[1] = "Explore the Blockchain" + self.user_menu[2] = "Transfer coins" + self.user_menu[3] = "Cancel transaction" + self.user_menu[4] = "Check balance" + self.user_menu[5] = "Check the pool" + self.user_menu[6] = "Mine a block" + + self.opened_logs = False + + def printMenu(self, items): + for key, value in items.items(): + print(f'{key} -- {value}') + + def runStartMenu(self): + while(True): + self.printMenu(self.start_menu) + # make input an interger + try: + choice = int(input()) + except: + self.clearScreen() + print("Wrong input, try again") + continue + self.clearScreen() + + # check if choice is in menu + match self.start_menu[choice]: + case "Exit": + print('Exiting system') + exit() + + case "Explore the Blockchain": + pass + + case "Login": + user = User(self.db) + logged_in = user.login() + self.clearScreen() + if logged_in: + print(f'Welcome {user.username}') + return user + print("Login failed") + + case "Sign up": + new_user = User(self.db) + registered = new_user.register() + if registered: + print("Registration successful") + return new_user + print("Registration failed") + + case _: + print("Wrong input, try again") + + def runUserMenu(self, user): + while(True): + self.printMenu(self.user_menu) + # make input an interger + try: + choice = int(input()) + except: + self.clearScreen() + print("Wrong input, try again") + continue + self.clearScreen() + + # check if choice is in menu + match self.user_menu[choice]: + case "Log out": + user.logout() + + case "Explore the Blockchain": + pass + + case "Transfer coins": + pass + + case "Cancel transaction": + pass + + case "Check balance": + pass + + case "Check the pool": + pass + + case "Mine a block": + pass + + case _: + print("Wrong input, try again") + + def clearScreen(self): + os.system('cls' if os.name == 'nt' else 'clear') \ No newline at end of file diff --git a/goodchain/src/main.py b/goodchain/src/main.py new file mode 100644 index 0000000..8814b12 --- /dev/null +++ b/goodchain/src/main.py @@ -0,0 +1,25 @@ +""" +----------------------v1.0.0---------------------- + ____ _ _ _ + / ___| ___ ___ __| | ___| |__ __ _(_)_ __ +| | _ / _ \ / _ \ / _` |/ __| '_ \ / _` | | '_ \ +| |_| | (_) | (_) | (_| | (__| | | | (_| | | | | | + \____|\___/ \___/ \__,_|\___|_| |_|\__,_|_|_| |_| + +------------------Ryan & Teuntje------------------ +""" +from helpers.DatabaseHelper import DatabaseHelper +from helpers.MenuHelper import MenuHelper + +if __name__ == "__main__": + # start db connection + db = DatabaseHelper("goodchain.db") + db.checkMigrations() + + # start menu + menu = MenuHelper(db) + while(True): + user = menu.runStartMenu() + + if user: + menu.runUserMenu(user) \ No newline at end of file