login
Added login functionality. It's a bit clunky, but it deas what it needs to. Testing needed. The header now has a search bar, but the page itself needs to be created.
This commit is contained in:
parent
d4016ce80c
commit
dda864a92e
|
@ -235,6 +235,7 @@
|
||||||
<x:Array Type="sys:Object">
|
<x:Array Type="sys:Object">
|
||||||
<sys:String>ID</sys:String>
|
<sys:String>ID</sys:String>
|
||||||
<sys:String>SESSKEY</sys:String>
|
<sys:String>SESSKEY</sys:String>
|
||||||
|
<sys:String>USERID</sys:String>
|
||||||
<sys:String>CREATED</sys:String>
|
<sys:String>CREATED</sys:String>
|
||||||
<sys:String>LIFE</sys:String>
|
<sys:String>LIFE</sys:String>
|
||||||
</x:Array>
|
</x:Array>
|
||||||
|
|
57
flask/app.py
57
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 datetime import datetime
|
||||||
|
from hashlib import sha256
|
||||||
|
from uuid import uuid4 as uuid
|
||||||
## Import db class from func.py and initialise it
|
## Import db class from func.py and initialise it
|
||||||
from func import db
|
from func import db
|
||||||
db=db()
|
db=db()
|
||||||
|
db.startup()
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@ -12,7 +15,7 @@ app = Flask(__name__)
|
||||||
def timectime(s):
|
def timectime(s):
|
||||||
return datetime.utcfromtimestamp(s).strftime('%Y-%m-%d %H:%M')
|
return datetime.utcfromtimestamp(s).strftime('%Y-%m-%d %H:%M')
|
||||||
@app.template_filter('spacer')
|
@app.template_filter('spacer')
|
||||||
def timectime(s):
|
def convsize(s):
|
||||||
sizes=("B","KB","MB","GB","TB")
|
sizes=("B","KB","MB","GB","TB")
|
||||||
n=0
|
n=0
|
||||||
while s > 1000:
|
while s > 1000:
|
||||||
|
@ -20,12 +23,58 @@ def timectime(s):
|
||||||
s=s/1000
|
s=s/1000
|
||||||
return str("%.2f" % s)+sizes[n]
|
return str("%.2f" % s)+sizes[n]
|
||||||
|
|
||||||
|
|
||||||
## WEB FRONTEND
|
## WEB FRONTEND
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def homepage():
|
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()
|
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/<userid>')
|
||||||
|
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 "<h2>You've entered the wrong password. This incident will be reported.</h2><br> Go back and try again.<br>" + password.upper() + "<br>" + 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
|
## API CALLS
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
## MAIN FUNCTIONS FILE FOR BACK-BACKEND OF FLASK
|
## MAIN FUNCTIONS FILE FOR BACK-BACKEND OF FLASK
|
||||||
import mariadb as sql
|
import mariadb as sql
|
||||||
from os import environ
|
from os import environ
|
||||||
|
import time
|
||||||
|
|
||||||
## params populated with environment variables, defaults can be changed for a permanent solution
|
## params populated with environment variables, defaults can be changed for a permanent solution
|
||||||
conn_params={
|
conn_params={
|
||||||
|
@ -13,13 +14,13 @@ conn_params={
|
||||||
class db:
|
class db:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.conn=sql.connect(**conn_params)
|
self.conn=sql.connect(**conn_params)
|
||||||
|
self.conn.autocommit=True
|
||||||
self.cur=self.conn.cursor()
|
self.cur=self.conn.cursor()
|
||||||
|
|
||||||
## Creates all archives, if they don't exist already
|
## Creates all archives, if they don't exist already
|
||||||
## Called only on startup, hence the name
|
## Called only on startup, hence the name
|
||||||
def startup(self):
|
def startup(self):
|
||||||
self.cur.execute("""
|
self.cur.execute("""CREATE TABLE IF NOT EXISTS Archs(
|
||||||
CREATE TABLE IF NOT EXISTS Archs(
|
|
||||||
ID int PRIMARY KEY AUTO_INCREMENT,
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
NAME text NOT NULL,
|
NAME text NOT NULL,
|
||||||
HASH text NOT NULL,
|
HASH text NOT NULL,
|
||||||
|
@ -27,44 +28,77 @@ class db:
|
||||||
IMPORTED int,
|
IMPORTED int,
|
||||||
CATEGORY int,
|
CATEGORY int,
|
||||||
OWNER int
|
OWNER int
|
||||||
);
|
);""")
|
||||||
CREATE TABLE IF NOT EXISTS Users(
|
self.cur.execute("""CREATE TABLE IF NOT EXISTS Users(
|
||||||
ID int PRIMARY KEY AUTO_INCREMENT,
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
UNAME text NOT NULL,
|
UNAME text NOT NULL,
|
||||||
DNAME text NOT NULL,
|
DNAME text NOT NULL,
|
||||||
CREATED int NOT NULL,
|
CREATED int NOT NULL,
|
||||||
STATE text,
|
STATE text,
|
||||||
PASSHASH text NOT NULL
|
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,
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
SESSKEY text NOT NULL,
|
SESSKEY text NOT NULL,
|
||||||
|
USERID int NOT NULL,
|
||||||
CREATED int NOT NULL,
|
CREATED int NOT NULL,
|
||||||
LIFE int
|
LIFE int
|
||||||
);
|
);""")
|
||||||
CREATE TABLE IF NOT EXISTS Cats(
|
self.cur.execute("""CREATE TABLE IF NOT EXISTS Cats(
|
||||||
ID int PRIMARY KEY AUTO_INCREMENT,
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
CATEGORY text NOT NULL,
|
CATEGORY text NOT NULL,
|
||||||
PARENT int,
|
PARENT int,
|
||||||
DESCRIPTION text
|
DESCRIPTION text
|
||||||
);
|
);""")
|
||||||
CREATE TABLE IF NOT EXISTS ArchLab(
|
self.cur.execute("""CREATE TABLE IF NOT EXISTS ArchLab(
|
||||||
ID int PRIMARY KEY AUTO_INCREMENT,
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
ARCHID int NOT NULL,
|
ARCHID int NOT NULL,
|
||||||
LABID 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,
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
LABEL text NOT NULL,
|
LABEL text NOT NULL,
|
||||||
CATEGORY text,
|
CATEGORY text,
|
||||||
TYPE int NOT NULL
|
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,
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
NAME text NOT NULL,
|
NAME text NOT NULL,
|
||||||
DESCRIPTION text
|
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
|
## 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)
|
## 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
|
return archive, labels
|
||||||
|
|
||||||
## Returns n archives, sorted by (imported )time or size
|
## 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):
|
def get_n_archives(self, sorttype:str="time",category:int=0, count:int=20):
|
||||||
global cur
|
global cur
|
||||||
match sorttype:
|
match sorttype:
|
||||||
|
@ -94,7 +128,7 @@ class db:
|
||||||
sorttype="SIZE"
|
sorttype="SIZE"
|
||||||
case _:
|
case _:
|
||||||
sorttype="IMPORTED"
|
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()
|
archives=self.cur.fetchall()
|
||||||
return archives
|
return archives
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ header > div#container {
|
||||||
}
|
}
|
||||||
|
|
||||||
.big-button {
|
.big-button {
|
||||||
width: 2em;
|
|
||||||
height: 2em;
|
height: 2em;
|
||||||
margin: auto 0.1em;
|
margin: auto 0.1em;
|
||||||
border: none;
|
border: none;
|
||||||
|
|
|
@ -6,6 +6,13 @@ div.grid-item {
|
||||||
border: 2px black solid;
|
border: 2px black solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.grid-item {
|
||||||
|
text-decoration: none;
|
||||||
|
display: contents;
|
||||||
|
height: 100%;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
div.clickable:hover {
|
div.clickable:hover {
|
||||||
background: grey;
|
background: lightgrey;
|
||||||
}
|
}
|
9
flask/static/login.css
Normal file
9
flask/static/login.css
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -11,7 +11,15 @@
|
||||||
<header>
|
<header>
|
||||||
<span id="title">{{title}}</span>
|
<span id="title">{{title}}</span>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<button class="big-button">🔎</div>
|
<form action="/search" method="get">
|
||||||
|
<input type="text" name="q" placeholder="search">
|
||||||
|
<input type="submit" value="🔎" class="big-button" id="search-button">
|
||||||
|
</form>
|
||||||
|
{% if login %}
|
||||||
|
<a href="/user/{{userdata[0]}}"><button class="big-button">{{userdata[2]}}</button></a>
|
||||||
|
{% else %}
|
||||||
|
<a href="/login"><button class="big-button">Login</button></a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
{% if archives|length > 0 %}
|
{% if archives|length > 0 %}
|
||||||
<div class="grid-container">
|
<div class="grid-container">
|
||||||
{% for arch in archives %}
|
{% for arch in archives %}
|
||||||
<div class="grid-item clickable"><b>{{arch[0]}}</b></div>
|
<a class="grid-item" href="/view/{{arch[0]}}"><div class="grid-item clickable"><b>{{arch[1]}}</b></div></a>
|
||||||
<div class="grid-item"><p>{{arch[1]|spacer}}</p></div>
|
<div class="grid-item"><p>{{arch[2]|spacer}}</p></div>
|
||||||
<div class="grid-item"><p>{{arch[2]|ctime}}</p></div>
|
<div class="grid-item"><p>{{arch[3]|ctime}}</p></div>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
15
flask/templates/login.html
Normal file
15
flask/templates/login.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block meta %}
|
||||||
|
<link rel="stylesheet" href="/static/login.css" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/login" method="post">
|
||||||
|
<div class="grid-container">
|
||||||
|
<span>Username: </span><input type="text" name="username" placeholder="Username">
|
||||||
|
<span>Password: </span><input type="password" name="password" placeholder="******">
|
||||||
|
<input type = 'submit' value = 'Login'/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
|
@ -1 +1,3 @@
|
||||||
flask
|
flask
|
||||||
|
mariadb
|
||||||
|
hashlib
|
Loading…
Reference in a new issue