diff --git a/ER-rar-index.graphml b/ER-rar-index.graphml index 52f96ae..6ed562a 100644 --- a/ER-rar-index.graphml +++ b/ER-rar-index.graphml @@ -235,6 +235,7 @@ ID SESSKEY + USERID CREATED LIFE diff --git a/flask/app.py b/flask/app.py index f18152b..5a329e9 100644 --- a/flask/app.py +++ b/flask/app.py @@ -1,9 +1,12 @@ -from flask import Flask,redirect,url_for,request,render_template +from flask import Flask,redirect,url_for,request,render_template,make_response from datetime import datetime +from hashlib import sha256 +from uuid import uuid4 as uuid ## Import db class from func.py and initialise it from func import db db=db() +db.startup() app = Flask(__name__) @@ -12,7 +15,7 @@ app = Flask(__name__) def timectime(s): return datetime.utcfromtimestamp(s).strftime('%Y-%m-%d %H:%M') @app.template_filter('spacer') -def timectime(s): +def convsize(s): sizes=("B","KB","MB","GB","TB") n=0 while s > 1000: @@ -20,12 +23,58 @@ def timectime(s): s=s/1000 return str("%.2f" % s)+sizes[n] - ## WEB FRONTEND @app.route('/') def homepage(): + # try to get sesskey, else logout state + try: + # get sesskey and get info about user + sesskey=request.cookies.get('session') + res,userid=db.check_sesskey(sesskey) + if not res: + return 500 + userdata=db.get_user_info(userid) + logged_in=True + except Exception as e: + logged_in=False + userdata=() + archives=db.get_n_archives() - return render_template("home.html", title="Homepage",archives=archives) + return render_template("home.html", title="Homepage",userdata=userdata,login=logged_in,archives=archives) + +@app.route('/user') +@app.route('/user/') +def userpage(userid:int=0): + if userid==0: + return make_response(redirect('/')) + +@app.route('/login', methods=["GET","POST"]) +def loginpage(): + # POST: Process login request + if request.method == 'POST': + username=request.form['username'] + password=sha256(request.form['password'].encode()).hexdigest() + code,userid,passhash=db.get_passhash(username) + if code != 200: + return passhash + # if passwords match, create session and return cookie + if password.upper() == passhash.upper(): + lifetime=3000000 # lifetime of the sesskey in seconds + sesskey=str(uuid()) + db.set_sesskey(sesskey,userid,lifetime) + resp=setcookie("session",sesskey,lifetime) + return resp + else: + return "

You've entered the wrong password. This incident will be reported.


Go back and try again.
" + password.upper() + "
" + passhash.upper() # TODO: DELETE + # GET: Login form + else: + return render_template("login.html", title="Login") + +## FUNCTIONS +def setcookie(name:str,value:str,lifetime:int=10000): + resp = make_response(redirect('/')) + resp.set_cookie(name, value, max_age=lifetime) + return resp ## API CALLS diff --git a/flask/func.py b/flask/func.py index 6b589c3..55e4a8c 100644 --- a/flask/func.py +++ b/flask/func.py @@ -1,6 +1,7 @@ ## MAIN FUNCTIONS FILE FOR BACK-BACKEND OF FLASK import mariadb as sql from os import environ +import time ## params populated with environment variables, defaults can be changed for a permanent solution conn_params={ @@ -13,13 +14,13 @@ conn_params={ class db: def __init__(self): self.conn=sql.connect(**conn_params) + self.conn.autocommit=True self.cur=self.conn.cursor() ## Creates all archives, if they don't exist already ## Called only on startup, hence the name def startup(self): - self.cur.execute(""" - CREATE TABLE IF NOT EXISTS Archs( + self.cur.execute("""CREATE TABLE IF NOT EXISTS Archs( ID int PRIMARY KEY AUTO_INCREMENT, NAME text NOT NULL, HASH text NOT NULL, @@ -27,44 +28,77 @@ class db: IMPORTED int, CATEGORY int, OWNER int - ); - CREATE TABLE IF NOT EXISTS Users( + );""") + self.cur.execute("""CREATE TABLE IF NOT EXISTS Users( ID int PRIMARY KEY AUTO_INCREMENT, UNAME text NOT NULL, DNAME text NOT NULL, CREATED int NOT NULL, STATE text, PASSHASH text NOT NULL - ); - CREATE TABLE IF NOT EXISTS Sessions( + );""") + self.cur.execute("""CREATE TABLE IF NOT EXISTS Sessions( ID int PRIMARY KEY AUTO_INCREMENT, SESSKEY text NOT NULL, + USERID int NOT NULL, CREATED int NOT NULL, LIFE int - ); - CREATE TABLE IF NOT EXISTS Cats( + );""") + self.cur.execute("""CREATE TABLE IF NOT EXISTS Cats( ID int PRIMARY KEY AUTO_INCREMENT, CATEGORY text NOT NULL, PARENT int, DESCRIPTION text - ); - CREATE TABLE IF NOT EXISTS ArchLab( + );""") + self.cur.execute("""CREATE TABLE IF NOT EXISTS ArchLab( ID int PRIMARY KEY AUTO_INCREMENT, ARCHID int NOT NULL, LABID int NOT NULL - ); - CREATE TABLE IF NOT EXISTS Labs( + );""") + self.cur.execute("""CREATE TABLE IF NOT EXISTS Labs( ID int PRIMARY KEY AUTO_INCREMENT, LABEL text NOT NULL, CATEGORY text, TYPE int NOT NULL - ); - CREATE TABLE IF NOT EXISTS LabType( + );""") + self.cur.execute("""CREATE TABLE IF NOT EXISTS LabType( ID int PRIMARY KEY AUTO_INCREMENT, NAME text NOT NULL, DESCRIPTION text - ); - """) + );""") + + ## Gets the passhash from a specific user + ## OUTPUT: (If user exists) int=200, passhash:str + ## (If user does not exist) int=400, Exception:str + def get_passhash(self, username:str): + self.cur.execute(f"SELECT ID,PASSHASH FROM Users WHERE UNAME='{username}'") + try: + resp=self.cur.fetchone() + except Exception as e: + return 400, e, NULL + return 200, resp[0], resp[1] + + ## Checks if sesskey exists and is not expired + ## OUTPUT: (if valiid) bool=True, USERID:str + ## (in invalid) bool=False, str="" + def check_sesskey(self, sesskey:str): + self.cur.execute(f"SELECT SESSKEY,USERID FROM Sessions WHERE SESSKEY='{sesskey}'") + entry=self.cur.fetchone() + if sesskey in entry: + return True, entry[1] + else: + return False, "" + + ## Sets a session key. That's it. + def set_sesskey(self, sesskey:str, userid:int, lifetime:int): + self.cur.execute(f"INSERT INTO Sessions(SESSKEY,USERID,CREATED,LIFE) VALUES('{sesskey}',{userid},{time.time()},{lifetime})") + + ## Gets and returns all user info about one (1) user + ## OUTPUT: tuple=(ID:int,UNAME:str,DNAME:str,CREATED:int,STATE:text,PASSHASH:text) + def get_user_info(self, userid:int): + print("USERID:::::::::::" + userid) + self.cur.execute(f"SELECT * FROM Users WHERE ID='{userid}'") + return self.cur.fetchone() ## Returns all relevant information about one (1) archive ## OUTPUT: archive:tuple=(NAME:str,HASH:str,IMPORTED[UNIX]:int,CATEGORY,str,CATEGORY.DESCRIPTION:str,UNAME:str,DNAME:str) @@ -86,7 +120,7 @@ class db: return archive, labels ## Returns n archives, sorted by (imported )time or size - ## OUTPUT: archives:array=[…,(NAME:str,SIZE:str,IMPORTED[UNIX]:int),…] + ## OUTPUT: archives:array=[…,(ID:int,NAME:str,SIZE:str,IMPORTED[UNIX]:int),…] def get_n_archives(self, sorttype:str="time",category:int=0, count:int=20): global cur match sorttype: @@ -94,7 +128,7 @@ class db: sorttype="SIZE" case _: sorttype="IMPORTED" - self.cur.execute(f"""SELECT NAME,SIZE,IMPORTED FROM Archs{"" if category==0 else " WHERE CATEGORY=" + category} ORDER BY {sorttype} DESC LIMIT {count};""") + self.cur.execute(f"""SELECT ID,NAME,SIZE,IMPORTED FROM Archs{"" if category==0 else " WHERE CATEGORY=" + category} ORDER BY {sorttype} DESC LIMIT {count};""") archives=self.cur.fetchall() return archives diff --git a/flask/static/base.css b/flask/static/base.css index cce6ae8..30291ea 100644 --- a/flask/static/base.css +++ b/flask/static/base.css @@ -23,7 +23,6 @@ header > div#container { } .big-button { - width: 2em; height: 2em; margin: auto 0.1em; border: none; diff --git a/flask/static/home.css b/flask/static/home.css index 5ccd682..dc61c44 100644 --- a/flask/static/home.css +++ b/flask/static/home.css @@ -6,6 +6,13 @@ div.grid-item { border: 2px black solid; } +a.grid-item { + text-decoration: none; + display: contents; + height: 100%; + color: black; +} + div.clickable:hover { - background: grey; + background: lightgrey; } \ No newline at end of file diff --git a/flask/static/login.css b/flask/static/login.css new file mode 100644 index 0000000..9d2e21a --- /dev/null +++ b/flask/static/login.css @@ -0,0 +1,9 @@ +div.grid-container { + margin: 2em 0 0 1em; + display: inline-grid; + grid-template-columns: auto auto; +} + +div.grid-container > * { + margin: 1em auto; +} \ No newline at end of file diff --git a/flask/templates/base.html b/flask/templates/base.html index a58cf17..f8326ab 100644 --- a/flask/templates/base.html +++ b/flask/templates/base.html @@ -11,7 +11,15 @@
{{title}}
-
+
+ + +
+ {% if login %} + + {% else %} + + {% endif %}
diff --git a/flask/templates/home.html b/flask/templates/home.html index d5d0582..c59f1fb 100644 --- a/flask/templates/home.html +++ b/flask/templates/home.html @@ -8,9 +8,9 @@ {% if archives|length > 0 %}
{% for arch in archives %} -
{{arch[0]}}
-

{{arch[1]|spacer}}

-

{{arch[2]|ctime}}

+
{{arch[1]}}
+

{{arch[2]|spacer}}

+

{{arch[3]|ctime}}

{% endfor %}
diff --git a/flask/templates/login.html b/flask/templates/login.html new file mode 100644 index 0000000..6fb0c68 --- /dev/null +++ b/flask/templates/login.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block meta %} + +{% endblock %} + +{% block content %} +
+
+ Username: + Password: + +
+
+{% endblock %} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 8ab6294..f0b97de 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ -flask \ No newline at end of file +flask +mariadb +hashlib \ No newline at end of file