From b18624266a0571db9cfe065442a4360f49e05e55 Mon Sep 17 00:00:00 2001 From: white <122345776@umail.ucc.ie> Date: Fri, 17 Jan 2025 13:55:17 +0000 Subject: [PATCH] Implemented login and session functionality, created a database on the backend to store login and stream information --- core/__pycache__/app.cpython-310.pyc | Bin 2401 -> 2381 bytes core/app.py | 74 +++++++++++++++++++++++++-- core/database.py | 15 ++++++ database/app.db | 0 database/schema.sql | 33 ++++++++++++ 5 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 core/database.py create mode 100644 database/app.db create mode 100644 database/schema.sql diff --git a/core/__pycache__/app.cpython-310.pyc b/core/__pycache__/app.cpython-310.pyc index 26ad86bc7a033908aab0244125490aa5823db8c7..3936b638b66dac19195c5dee73d82de5056f266c 100644 GIT binary patch delta 457 zcmaDTbXJHrpO=@50SG4DZcl%;k#`*<(=CR{7a1$q#DIcDVw3%u3K%6OA7FaGC^C5= zvjId{eDZZ>KT#!+3T3b|5TOVn#3x&^C^M=7HOMd(Nlva|ne8hI5|;uI(m+C!t%w7} z28*(TSZpAI6-3B_2ssb|HVf*?#xIXd83)#dNwI=Uio5(0M*^6CIUI-*-2qKI?gfUzx z#1)gLvnw;2PTtM#6QT!{(qt*(1F6sl5n!zbAW`Nb6Sx4_7=*Q82Z2Jt9EgiSLC(g+ x!N>u`EX+kxlcPCin@WK6s(}a%AaRSeD8IBMwMYvjUM(6iGXTBjPecF! delta 457 zcmYk1y-EW?6os8l_D5mG#NF9MBCf_{*##%vIA_1B}3z)TVx-qLPr6+T5Cz7KuFBXw# z0BSXcn-lG+p=$m$U{I#m@>rR6tx?B=Q3C>ru`c>ompu`}NCEZR*}hVoy!q}Qm=jHS diff --git a/core/app.py b/core/app.py index e0420f5..ddce27b 100644 --- a/core/app.py +++ b/core/app.py @@ -1,10 +1,17 @@ from flask import Flask, render_template, session, request, url_for, redirect, g +from flask_session import Session from werkzeug.security import generate_password_hash, check_password_hash from functools import wraps + from core.forms import SignupForm, LoginForm +from core.database import Database app = Flask(__name__, template_folder="../ui/templates/") app.config["SECRET_KEY"] = "" +app.config["SESSION_PERMANENT"] = False +app.config["SESSION_TYPE"] = "filesystem" +app.teardown_appcontext(Database.close_connection) +Session(app) @app.before_request def logged_in_user(): @@ -21,7 +28,7 @@ def login_required(view): return wrapped_view def admin_required(view): - """add at start of routes where users admin needs to be logged in to access""" + """add at start of routes where admins need to be logged in to access""" @wraps(view) def wrapped_view(*args, **kwargs): if g.admin != "admin": @@ -49,8 +56,33 @@ def signup(): password = form.password.data password2 = form.password2.data - # Store in database - return + # Store in database and hash to avoid exposing sensitive information + db = Database() + cursor = db.create_connection("../database/app.db") + + # Check if user already exists to avoid duplicates + dup_email = cursor.execute("""SELECT * FROM users + WHERE email = ?;""", (email,)).fetchone() + dup_username = cursor.execute("""SELECT * FROM users + WHERE username = ?;""", (username,)).fetchone() + + if dup_email is not None: + form.email.errors.append("Email already taken.") + elif dup_username is not None: + form.username.errors.append("Username already taken.") + elif password != password2: + form.password.errors.append("Passwords must match.") + else: + db.execute("""INSERT INTO users (username, password, email, num_followers, isPartenered, bio) + VALUES (?, ?, ?, ?, ?, ?);""", (username, generate_password_hash(password), email, 0, 0, "This user does not have a Bio.")) + db.commit() + return redirect(url_for("login")) + + + # Close connection to prevent data leaks + db.close_connection() + + return render_template("signup.html", form=form) @app.route("/login", methods=["GET", "POST"]) def login(): @@ -61,4 +93,38 @@ def login(): password = form.username.data # Compare with database - return + db = Database() + cursor = db.create_connection("../database/app.db") + + # Check if user exists so only users who have signed up can login + user_exists = cursor.execute("""SELECT * FROM users + WHERE username = ?;""", (username,)).fetchone() + db.close_connection() + + if not user_exists: + form.username.errors.append("Incorrect username or password.") + + # Check is hashed passwords match to verify the user logging in + elif not check_password_hash(user_exists["password"], password): + form.username.errors.append("Incorrect username or password.") + + else: + # Create a new session to prevent users from exploiting horizontal access control + session.clear() + session["username"] = username + + # Return to previous page if applicable + next_page = request.args.get("next") + + # Otherwise return home + if not next_page: + next_page = url_for("index") + return redirect(next_page) + + return render_template("login.html", form=form) + +@app.route("/logout") +@login_required +def logout(): + session.clear() + return redirect(url_for("index")) \ No newline at end of file diff --git a/core/database.py b/core/database.py new file mode 100644 index 0000000..d3ded0e --- /dev/null +++ b/core/database.py @@ -0,0 +1,15 @@ +import sqlite3 + +class Database: + def __init__(self, db:str) -> None: + self._db = db + self._conn = None + + def create_connection(self) -> sqlite3.Cursor: + conn = sqlite3.connect(self._db) + self._conn = conn + cursor = conn.cursor() + return cursor + + def close_connection(self) -> None: + self._conn.close() \ No newline at end of file diff --git a/database/app.db b/database/app.db new file mode 100644 index 0000000..e69de29 diff --git a/database/schema.sql b/database/schema.sql new file mode 100644 index 0000000..96f9ae8 --- /dev/null +++ b/database/schema.sql @@ -0,0 +1,33 @@ +DROP TABLE IF EXISTS users; +CREATE TABLE users +( + username VARCHAR(50) PRIMARY KEY NOT NULL, + password VARCHAR(256) NOT NULL, + email VARCHAR(64) NOT NULL, + num_followers INTEGER NOT NULL, + isPartenered BOOLEAN NOT NULL DEFAULT 0 + bio TEXT, +); + +DROP TABLE IF EXISTS streams; +CREATE TABLE streams +( + stream_id INTEGER PRIMARY KEY AUTOINCREMENT, + title TEXT NOT NULL, + start_time DATETIME NOT NULL, + num_viewers INT NOT NULL DEFAULT 0, + isLive BOOLEAN NOT NULL DEFAULT 0, + vod_id INT, + streamer_id VARCHAR NOT NULL, + FOREIGN KEY (streamer_id) REFERENCES users(username) ON DELETE CASCADE +); + +DROP TABLE IF EXISTS follows; +CREATE TABLE follows +( + user_id INT NOT NULL, + following_id INT NOT NULL, + PRIMARY KEY (user_id, following_id), + FOREIGN KEY (user_id) REFERENCES users(username) ON DELETE CASCADE, + FOREIGN KEY (following_id) REFERENCES users(username) ON DELETE CASCADE +); \ No newline at end of file