diff --git a/.gitignore b/.gitignore index 305b006..9ec588a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ application/__pycache__/ application/session_data.json bank.db test_database.db +log.txt # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/application/app.ini b/application/app.ini index e0ea061..903ac4c 100644 --- a/application/app.ini +++ b/application/app.ini @@ -8,6 +8,6 @@ dark_theme = dark theme = dark-blue [client] -default_id = d18e5ae0 -default_password = KFCKrusher1 +default_id = 9ce7d233 +default_password = Happymeal1 diff --git a/application/session_data.json b/application/session_data.json index 30ecf10..349ebf8 100644 --- a/application/session_data.json +++ b/application/session_data.json @@ -1 +1 @@ -{"session_cookie": {"session": "fhCFtlJIX2pSU0z4Cn4yMBZpKa4WAEBGJLu00aGXOtc"}, "client_id": "d18e5ae0"} \ No newline at end of file +{"session_cookie": {"session": "m4rjEuzC595awmTv39qVOhjiiQYDcq3PT7ObB1_S6Bs"}, "client_id": "9ce7d233"} \ No newline at end of file diff --git a/emailer.py b/emailer.py index 3ba6806..6ec6404 100644 --- a/emailer.py +++ b/emailer.py @@ -1,3 +1,6 @@ +# Lucas Mathews - Fontys Student ID: 5023572 +# Banking System Manager File + import smtplib import ssl from email.mime.text import MIMEText @@ -30,10 +33,12 @@ def send_email(receiver_email, subject, body): with smtplib.SMTP_SSL(CONFIG["smtp"]["host"], CONFIG["smtp"]["port"], context=context) as server: server.login(CONFIG["smtp"]["username"], CONFIG["smtp"]["password"]) server.sendmail(sender_email, receiver_email, text) - print(f"Email sent to {receiver_email}.") + from manager import log_event + log_event(f"Email '{subject}' sent to {receiver_email}") # Log the message except Exception as e: error_message = f"Failed to send email to {receiver_email}: {e}" - print(error_message) + from manager import log_event + log_event(error_message) # Log the error raise EmailSendingError(error_message) diff --git a/manager.py b/manager.py index f823b47..0397802 100644 --- a/manager.py +++ b/manager.py @@ -86,6 +86,12 @@ def check_expired_otps(): for client_id in expired_otps: delete_otp(client_id) +def log_event(data_to_log:str): + """Logs an event to the log file.""" + with open("log.txt", "a") as log_file: + log_file.write(f"{timestamp()} - {data_to_log}\n") + + ###################### ### Authentication ### ###################### @@ -95,10 +101,10 @@ def login(): data = request.get_json() client_id = data.get('client_id') client_hash = data.get('client_hash') - client = session.query(Client).filter_by(client_id=client_id).first() if client and client.hash == client_hash: flask_session['client_id'] = client_id + log_event(f"{client_id} logged in successfully.") return format_response(True, f"{flask_session['client_id']} logged in successfully."), 200 return format_response(False, "Invalid client_id or password."), 401 @@ -188,7 +194,6 @@ def update_client(client_id:str, otp_code:int, **kwargs): return format_response(False, "Invalid OTP."), 400 # Changed to 400 Bad Request if not is_admin and client_id != current_client_id: return format_response(False, "You can only view your own client information."), 403 - client = session.query(Client).filter_by(client_id=client_id).first() if client: for field in ['name', 'birthdate', 'address', 'phone_number', 'email', 'notes']: @@ -196,7 +201,6 @@ def update_client(client_id:str, otp_code:int, **kwargs): setattr(client, field, kwargs[field]) session.commit() return format_response(True, f"Client ID: {client_id} has been updated."), 200 - return format_response(False, "Client not found."), 404 @@ -208,37 +212,27 @@ def change_password(): hash_new_password = data.get('hash_new_password') otp_code = data.get('otp_code') current_client_id, is_admin = get_current_client() - - # Verify if the OTP is correct - otp_verified = verify_otp(client_id, otp_code) - - # Check if the client is authorized to change the password - if not is_admin and client_id != current_client_id: + otp_verified = verify_otp(client_id, otp_code) # Verify if the OTP is correct + if not is_admin and client_id != current_client_id: # Check if the client is authorized to change the password return format_response(False, "You can only update your own client information."), 401 - - # Recheck OTP verification after authorisation check - if not otp_verified: + if not otp_verified: # Recheck OTP verification after authorisation check return format_response(False, "Invalid OTP."), 400 - - # Validate new password format - hash_format = r'^[0-9a-f]{128}$' + hash_format = r'^[0-9a-f]{128}$' # Validate new password format if not re.match(hash_format, hash_new_password): return format_response(False, "Invalid new password format (must be provided as a hash)."), 400 - - # Check if the old password hash matches and update to the new password hash - client = session.query(Client).filter_by(client_id=client_id).first() + client = session.query(Client).filter_by(client_id=client_id).first() # Check if the old password hash matches and update to the new password hash if client: if client.hash == hash_old_password: client.hash = hash_new_password session.commit() delete_otp(client_id) - return format_response(True, f"Password for client_id: {client_id} has been updated."), 200 + log_event(f"Password for client_id {client_id} has been updated by {current_client_id}.") + return format_response(True, f"Password for client_id {client_id} has been updated."), 200 else: return format_response(False, "Invalid old password."), 400 else: return format_response(False, "Client not found."), 404 - @login_required def get_accounts(client_id: str): """Returns all accounts for a specific client in the database. If the client is not found, returns an error message.""" @@ -396,6 +390,7 @@ def delete_account(account_id:str): if account.balance == 0: session.delete(account) session.commit() + log_event(f"Account ID: {account_id} has been removed by {flask_session['client_id']}.") return format_response(True, f"account_id: {account_id} has been removed."), 200 else: return format_response(False, "Account has a balance and can not be removed."), 400 @@ -405,18 +400,21 @@ def delete_account(account_id:str): def get_all_clients(): """Returns all clients in the database.""" clients = session.query(Client).all() + log_event(f"All clients have been retrieved by {flask_session['client_id']}.") return format_response(True, "", [client.to_dict() for client in clients]), 200 @admin_required def get_all_accounts(): """Returns all accounts in the database.""" accounts = session.query(Account).all() + log_event(f"All accounts have been retrieved by {flask_session['client_id']}.") return format_response(True, "", [account.to_dict() for account in accounts]), 200 @admin_required def get_all_transactions(): """Returns all transactions in the database.""" transactions = session.query(Transaction).all() + log_event(f"All transactions have been retrieved by {flask_session['client_id']}.") return format_response(True, "", [transaction.to_dict() for transaction in transactions]), 200 @admin_required @@ -427,6 +425,7 @@ def apply_interest(account_id:int, interest_rate:float): interest = account.balance * interest_rate account.balance += interest session.commit() + log_event(f"Interest of €{interest} has been applied to Account ID: {account_id} by {flask_session['client_id']}.") return format_response(True, f"€{interest} in interest has been applied to Account ID: {account_id}."), 200 return format_response(False, "Account not found."), 404 @@ -437,6 +436,7 @@ def apply_fee(account_id:int, fee:float): if account.account_id == account_id: account.balance -= fee session.commit() + log_event(f"Fee of €{fee} has been applied to Account ID: {account_id} by {flask_session['client_id']}.") return format_response(True, f"€{fee} in fees has been applied to Account ID: {account_id}."), 200 return format_response(False, "Account not found."), 404 @@ -447,6 +447,7 @@ def delete_transaction(transaction_id:int): if transaction.transaction_id == transaction_id: session.delete(transaction) session.commit() + log_event(f"Transaction ID: {transaction_id} has been removed by {flask_session['client_id']}.") return format_response(True, f"Transaction ID: {transaction_id} has been removed."), 200 return format_response(False, "Transaction not found."), 404 @@ -457,6 +458,7 @@ def modify_balance(transaction_id:int, amount:int): if transaction.transaction_id == transaction_id: transaction.amount = amount session.commit() + log_event(f"Transaction ID: {transaction_id} has been modified by {flask_session['client_id']}.") return format_response(True, f"Transaction ID: {transaction_id} has been modified."), 200 return format_response(False, "Transaction not found."), 404 @@ -498,6 +500,7 @@ def initialise_database(password:str, email:str): admin_client = session.query(Client).filter_by(name='ADMINISTRATOR').one() # Retrieve the administrator client admin_client.administrator = 1 # Set the new client as an administrator session.commit() + log_event(f"Database initialised with administrator account with client_id {admin_client.client_id}.") return format_response(True, f"Database initialised with administrator account with client_id {admin_client.client_id}"), 200 return format_response(False, "Database not empty."), 400 @@ -508,6 +511,7 @@ def promote_to_admin(client_id:str): if client.client_id == client_id: client.administrator = 1 session.commit() + log_event(f"Client ID: {client_id} has been promoted to administrator by {flask_session['client_id']}.") return format_response(True, f"client_id: {client_id} has been promoted to administrator."), 200 return format_response(False, f"client_id: {client_id} is not found."), 404 @@ -518,6 +522,7 @@ def demote_from_admin(client_id:str): if client.client_id == client_id: client.administrator = 0 session.commit() + log_event(f"Client ID: {client_id} has been demoted from administrator by {flask_session['client_id']}.") return format_response(True, f"client_id: {client_id} has been demoted from administrator."), 200 return format_response(False, f"client_id: {client_id} is not found."), 404 diff --git a/test_database.db b/test_database.db index 83e5c1f..02b4063 100644 Binary files a/test_database.db and b/test_database.db differ diff --git a/test_database_generator.py b/test_database_generator.py index 42cb917..910d81e 100644 --- a/test_database_generator.py +++ b/test_database_generator.py @@ -119,6 +119,7 @@ session.commit() admin_client_id = session.query(Client.client_id).filter(Client.administrator == 1).first()[0] # Print the client_id of the administrator account -print(f"The client_id of the administrator account of this test database is: {admin_client_id}. The password is: Happymeal1") +print(f"The client_id of the administrator account of this test database is: {admin_client_id}") +print("The password is: Happymeal1") session.close() \ No newline at end of file