What I Built:
- A client-server application using sockets
- User login and account creation system
- Password hashing using SHA-256
- Basic encryption/decryption for data transmission
- Budget tracking system with stored user data
Key Skills Demonstrated:
- Secure authentication implementation
- Client-server communication (sockets)
- Data encryption and protection
- File handling and persistence (JSON)
- Python programming for security-focused applications
What I Learned:
- Importance of hashing passwords instead of storing plaintext
- How client-server systems communicate securely
- Challenges of handling authentication and user data
- Basics of securing data in transit and at rest
server.py
import socket
import json
import hashlib
import os
# Encryption/Decryption functions
def encrypt(data, key=5):
return ”.join(chr(ord(c) ^ key) for c in data)
def decrypt(data, key=5):
return encrypt(data, key)
# Load users from file
def load_users():
try:
with open(“users.json”, “r”) as f:
return json.load(f)
except FileNotFoundError:
return {}
# Save users to file
def save_users(users):
with open(“users.json”, “w”) as f:
json.dump(users, f)
# Hash password
def hash_password(password):
return hashlib.sha256(password.encode()).hexdigest()
# Authenticate user login
def authenticate(username, password_hash, users):
if username in users:
return users[username][“password”] == password_hash
return False
# Create account
def create_account(username, password_hash, users):
users[username] = {“password”: password_hash}
save_users(users)
return True
# Calculate recommended 50/30/20 budget
def calculate_budget(income):
return {
“needs”: round(income * 0.50, 2),
“wants”: round(income * 0.30, 2),
“savings”: round(income * 0.20, 2)
}
# Compare actual vs recommended expenses
def analyze_expenses(recommended, actual):
analysis = {}
if actual[“needs”] > recommended[“needs”]:
analysis[“needs_status”] = f”Over budget by ${round(actual[‘needs’] – recommended[‘needs’], 2)}”
else:
analysis[“needs_status”] = “Within recommended budget”
if actual[“wants”] > recommended[“wants”]:
analysis[“wants_status”] = f”Over budget by ${round(actual[‘wants’] – recommended[‘wants’], 2)}”
else:
analysis[“wants_status”] = “Within recommended budget”
if actual[“savings”] < recommended[“savings”]:
analysis[“savings_status”] = f”Below recommended savings by ${round(recommended[‘savings’] – actual[‘savings’], 2)}”
else:
analysis[“savings_status”] = “Meeting or exceeding savings goal”
return analysis
def save_budget_to_file(username, income, budget, actual, analysis):
filename = f”{username}_budget_history.json”
# Load existing history or create new
if os.path.exists(filename):
with open(filename, “r”) as f:
history = json.load(f)
else:
history = []
entry = {
“income”: income,
“recommended_budget”: budget,
“actual_expenses”: actual,
“analysis”: analysis
}
history.append(entry)
with open(filename, “w”) as f:
json.dump(history, f, indent=4)
# Main server function
def start_server(host=”127.0.0.1″, port=12345):
users = load_users()
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((host, port))
server_socket.listen()
print(f”Server running on {host}:{port}…”)
while True:
conn, addr = server_socket.accept()
print(f”Connected to {addr}”)
try:
login_data = decrypt(conn.recv(1024).decode())
username, password_hash, action = login_data.split(“,”)
if action == “login”:
if authenticate(username, password_hash, users):
conn.send(encrypt(“SUCCESS”).encode())
else:
conn.send(encrypt(“FAIL”).encode())
conn.close()
continue
elif action == “create”:
if username in users:
conn.send(encrypt(“EXISTS”).encode())
conn.close()
continue
else:
create_account(username, password_hash, users)
conn.send(encrypt(“CREATED”).encode())
encrypted_income = conn.recv(1024).decode()
income = float(decrypt(encrypted_income))
budget = calculate_budget(income)
conn.send(encrypt(json.dumps(budget)).encode())
expenses_encrypted = conn.recv(1024).decode()
actual_expenses = json.loads(decrypt(expenses_encrypted))
analysis = analyze_expenses(budget, actual_expenses)
save_budget_to_file(username, income, budget, actual_expenses, analysis)
conn.send(encrypt(json.dumps(analysis)).encode())
except Exception as e:
print(“Error:”, e)
finally:
conn.close()
print(f”Disconnected from {addr}”)
if __name__ == “__main__”:
start_server()
client .py
import socket
import json
SHIFT = 4
def encrypt(text):
return “”.join(chr((ord(c) + SHIFT) % 256) for c in text)
def decrypt(text):
return “”.join(chr((ord(c) – SHIFT) % 256) for c in text)
def send_request(sock, data):
encrypted = encrypt(json.dumps(data))
sock.send(encrypted.encode())
response = decrypt(sock.recv(4096).decode())
return json.loads(response)
# —————————–
# MAIN CLIENT
# —————————–
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((“127.0.0.1”, 5000))
print(“\n— Welcome to the Budget Tracker —“)
print(“1. Login”)
print(“2. Create Account”)
choice = input(“Choose: “)
username = input(“Username: “)
password = input(“Password: “)
if choice == “1”:
res = send_request(sock, {“action”: “login”, “username”: username, “password”: password})
else:
res = send_request(sock, {“action”: “register”, “username”: username, “password”: password})
if res[“status”] != “ok”:
print(res[“msg”])
return
print(“\nLogged in successfully!\n”)
while True:
print(“\n— Menu —“)
print(“1. Add Expense”)
print(“2. View Expense History”)
print(“3. Calculate 50/30/20 Budget”)
print(“4. Exit”)
option = input(“Choose: “)
if option == “1”:
item = input(“Expense name: “)
amount = float(input(“Amount: “))
res = send_request(sock, {“action”: “add_expense”, “username”: username, “item”: item, “amount”: amount})
print(res[“msg”])
elif option == “2”:
res = send_request(sock, {“action”: “get_history”, “username”: username})
print(“\n— Expense History —“)
for e in res[“history”]:
print(f”{e[‘item’]}: ${e[‘amount’]}”)
elif option == “3”:
income = float(input(“Monthly income: $”))
res = send_request(sock, {“action”: “budget”, “username”: username, “income”: income})
print(“\n— 50/30/20 Breakdown —“)
print(f”Needs: ${res[‘needs’]:.2f}”)
print(f”Wants: ${res[‘wants’]:.2f}”)
print(f”Savings: ${res[‘savings’]:.2f}”)
elif option == “4”:
print(“Goodbye!”)
sock.close()
break
else:
print(“Invalid choice.”)
if __name__ == “__main__”:
main()
Milestone-1