Implemented login and session functionality, created a database on the backend to store login and stream information
This commit is contained in:
Binary file not shown.
74
core/app.py
74
core/app.py
@@ -1,10 +1,17 @@
|
|||||||
from flask import Flask, render_template, session, request, url_for, redirect, g
|
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 werkzeug.security import generate_password_hash, check_password_hash
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from core.forms import SignupForm, LoginForm
|
from core.forms import SignupForm, LoginForm
|
||||||
|
from core.database import Database
|
||||||
|
|
||||||
app = Flask(__name__, template_folder="../ui/templates/")
|
app = Flask(__name__, template_folder="../ui/templates/")
|
||||||
app.config["SECRET_KEY"] = ""
|
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
|
@app.before_request
|
||||||
def logged_in_user():
|
def logged_in_user():
|
||||||
@@ -21,7 +28,7 @@ def login_required(view):
|
|||||||
return wrapped_view
|
return wrapped_view
|
||||||
|
|
||||||
def admin_required(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)
|
@wraps(view)
|
||||||
def wrapped_view(*args, **kwargs):
|
def wrapped_view(*args, **kwargs):
|
||||||
if g.admin != "admin":
|
if g.admin != "admin":
|
||||||
@@ -49,8 +56,33 @@ def signup():
|
|||||||
password = form.password.data
|
password = form.password.data
|
||||||
password2 = form.password2.data
|
password2 = form.password2.data
|
||||||
|
|
||||||
# Store in database
|
# Store in database and hash to avoid exposing sensitive information
|
||||||
return
|
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"])
|
@app.route("/login", methods=["GET", "POST"])
|
||||||
def login():
|
def login():
|
||||||
@@ -61,4 +93,38 @@ def login():
|
|||||||
password = form.username.data
|
password = form.username.data
|
||||||
|
|
||||||
# Compare with database
|
# 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"))
|
||||||
15
core/database.py
Normal file
15
core/database.py
Normal file
@@ -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()
|
||||||
0
database/app.db
Normal file
0
database/app.db
Normal file
33
database/schema.sql
Normal file
33
database/schema.sql
Normal file
@@ -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
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user