2023-10-17 18:25:38 +02:00
## MAIN FUNCTIONS FILE FOR BACK-BACKEND OF FLASK
import mariadb as sql
from os import environ
2023-10-19 13:25:59 +02:00
import time , re
2023-10-17 18:25:38 +02:00
## params populated with environment variables, defaults can be changed for a permanent solution
conn_params = {
" user " : environ . get ( ' MARIADB_USER ' ) if environ . get ( ' MARIADB_USER ' ) else " rar_index_app " ,
" password " : environ . get ( ' MARIADB_PASSWORD ' ) if environ . get ( ' MARIADB_PASSWORD ' ) else " password " ,
" host " : environ . get ( ' MARIADB_HOST ' ) if environ . get ( ' MARIADB_HOST ' ) else " marcelsite.com " ,
" database " : environ . get ( ' MARIADB_DB ' ) if environ . get ( ' MARIADB_DB ' ) else " rar_index "
}
class db :
def __init__ ( self ) :
self . conn = sql . connect ( * * conn_params )
2023-10-18 12:55:20 +02:00
self . conn . autocommit = True
2023-10-17 18:25:38 +02:00
self . cur = self . conn . cursor ( )
## Creates all archives, if they don't exist already
## Called only on startup, hence the name
def startup ( self ) :
2023-10-18 12:55:20 +02:00
self . cur . execute ( """ CREATE TABLE IF NOT EXISTS Archs(
2023-10-17 18:25:38 +02:00
ID int PRIMARY KEY AUTO_INCREMENT ,
NAME text NOT NULL ,
2023-10-19 13:25:59 +02:00
HASH text NOT NULL UNIQUE ,
2023-10-17 18:25:38 +02:00
SIZE int NOT NULL ,
IMPORTED int ,
CATEGORY int ,
OWNER int
2023-10-18 12:55:20 +02:00
) ; """ )
self . cur . execute ( """ CREATE TABLE IF NOT EXISTS Users(
2023-10-17 18:25:38 +02:00
ID int PRIMARY KEY AUTO_INCREMENT ,
UNAME text NOT NULL ,
DNAME text NOT NULL ,
CREATED int NOT NULL ,
STATE text ,
PASSHASH text NOT NULL
2023-10-18 12:55:20 +02:00
) ; """ )
self . cur . execute ( """ CREATE TABLE IF NOT EXISTS Sessions(
2023-10-17 18:25:38 +02:00
ID int PRIMARY KEY AUTO_INCREMENT ,
SESSKEY text NOT NULL ,
2023-10-18 12:55:20 +02:00
USERID int NOT NULL ,
2023-10-17 18:25:38 +02:00
CREATED int NOT NULL ,
LIFE int
2023-10-18 12:55:20 +02:00
) ; """ )
self . cur . execute ( """ CREATE TABLE IF NOT EXISTS Cats(
2023-10-17 18:25:38 +02:00
ID int PRIMARY KEY AUTO_INCREMENT ,
CATEGORY text NOT NULL ,
PARENT int ,
DESCRIPTION text
2023-10-18 12:55:20 +02:00
) ; """ )
self . cur . execute ( """ CREATE TABLE IF NOT EXISTS ArchLab(
2023-10-17 18:25:38 +02:00
ID int PRIMARY KEY AUTO_INCREMENT ,
ARCHID int NOT NULL ,
LABID int NOT NULL
2023-10-18 12:55:20 +02:00
) ; """ )
2023-10-19 13:25:59 +02:00
self . cur . execute ( """ CREATE TABLE IF NOT EXISTS CatLabType(
ID int PRIMARY KEY AUTO_INCREMENT ,
CATID int NOT NULL ,
LABID int NOT NULL
) ; """ )
2023-10-18 12:55:20 +02:00
self . cur . execute ( """ CREATE TABLE IF NOT EXISTS Labs(
2023-10-17 18:25:38 +02:00
ID int PRIMARY KEY AUTO_INCREMENT ,
LABEL text NOT NULL ,
TYPE int NOT NULL
2023-10-18 12:55:20 +02:00
) ; """ )
self . cur . execute ( """ CREATE TABLE IF NOT EXISTS LabType(
2023-10-17 18:25:38 +02:00
ID int PRIMARY KEY AUTO_INCREMENT ,
NAME text NOT NULL ,
DESCRIPTION text
2023-10-18 12:55:20 +02:00
) ; """ )
## 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 ) :
self . cur . execute ( f " SELECT * FROM Users WHERE ID= ' { userid } ' " )
return self . cur . fetchone ( )
2023-10-17 18:25:38 +02:00
2023-10-19 13:25:59 +02:00
## Checks information for errors and adds archive to the DB
## OUTPUT: (if successful) res:bool=True, ID:int
## (if unsuccessful) res:bool=False, str
def add_archive ( self , archive : dict ) :
# Check everything for errors or malicious things
archive [ " hash " ] = archive [ " hash " ] . upper ( )
if not re . match ( ' [A-Z0-9] {40} ' , archive [ " hash " ] ) :
return False , " Hash needs to be 40 characters in hexadecimal (SHA-1). "
if re . match ( ' .*[^A-Za-z0-9 \ . _-].* ' , archive [ " name " ] ) :
return False , " The name contains illegal characters. Allowed chars: ' [A-Za-z0-9 \ . _-] ' "
print ( archive [ " name " ] )
curtime = time . time ( )
try :
self . cur . execute ( f " INSERT INTO Archs(NAME,HASH,SIZE,IMPORTED,CATEGORY,OWNER) VALUES( ' { archive [ ' name ' ] } ' , ' { archive [ ' hash ' ] } ' , { archive [ ' size ' ] } , { curtime } , { archive [ ' category ' ] } , { archive [ ' owner ' ] } ) " )
except Exception as e : # hash needs to be unique
return False , e
self . cur . execute ( f " SELECT ID FROM Archs WHERE HASH= ' { archive [ ' hash ' ] } ' " )
archid = self . cur . fetchone ( )
return True , archid [ 0 ]
2023-10-17 18:25:38 +02:00
## Returns all relevant information about one (1) archive
2023-10-19 13:25:59 +02:00
## OUTPUT: archive:tuple=(NAME:str,HASH:str,IMPORTED[UNIX]:int,CATEGORY,str,CATEGORY.DESCRIPTION:str,UNAME:str,DNAME:str),
2023-10-17 18:25:38 +02:00
## labels:array=[…,(LABEL:str,CATEGORY:str,CATDESC:str,LABTYPE:str,LABDESC:str),…]
def get_archive_info ( self , hash : str ) :
self . cur . execute ( f """ SELECT Archs.NAME,Archs.HASH,Archs.IMPORTED,Cats.CATEGORY,Cats.DESCRIPTION,Users.UNAME,Users.DNAME FROM Archs
JOIN Cats ON Cats . ID = Archs . CATEGORY
JOIN Users ON Users . ID = Archs . OWNER
WHERE hash = ' {hash} ' """ )
archive = self . cur . fetchone ( )
self . cur . execute ( f """ SELECT Labs.LABEL,Cats.CATEGORY,Cats.DESCRIPTION AS CATDESC,LabType.NAME AS LABTYPE,LabType.DESCRIPTION AS LABDESC FROM ArchLab
JOIN Archs ON Archs . ID = ArchLab . ARCHID
JOIN Labs ON Labs . ID = ArchLab . LABID
JOIN Cats ON Labs . CATEGORY = Cats . ID
JOIN LabType ON Labs . TYPE = LabType . ID
WHERE ARCHID = 1 ; """ )
labels = self . cur . fetchall ( )
return archive , labels
2023-10-18 17:24:59 +02:00
## Returns all categories.
## OUTPUT: array=[…,(ID:int,CATEGORY:str,PARENT:int,DESCRIPTION:str),…]
def get_all_categories ( self ) :
self . cur . execute ( " SELECT * FROM Cats; " )
return self . cur . fetchall ( )
2023-10-17 18:25:38 +02:00
## Returns n archives, sorted by (imported )time or size
2023-10-18 12:55:20 +02:00
## OUTPUT: archives:array=[…,(ID:int,NAME:str,SIZE:str,IMPORTED[UNIX]:int),…]
2023-10-18 17:24:59 +02:00
def get_n_archives ( self , sorttype : str = " time " , category : int = 0 , keywords : list = [ ] , count : int = 20 ) :
2023-10-17 18:25:38 +02:00
match sorttype :
case " size " :
2023-10-18 17:24:59 +02:00
sorttype = " SIZE DESC "
case " time " :
sorttype = " IMPORTED DESC "
case " za " :
sorttype = " NAME DESC "
2023-10-17 18:25:38 +02:00
case _ :
2023-10-18 17:24:59 +02:00
sorttype = " NAME ASC "
# create SQL query for keywords
keyword_string = " "
for w in keywords :
keyword_string + = f " AND NAME LIKE ' % { w } % ' "
if len ( keywords ) == 1 :
for w in keywords :
keyword_string + = f " OR HASH = ' { w } ' "
# Get all children of category (if exist) and put into query string
categories = self . get_all_categories ( )
2023-10-19 13:25:59 +02:00
catlist = [ str ( category ) ]
2023-10-18 17:24:59 +02:00
for i in categories :
if i [ 2 ] == int ( category ) :
catlist . append ( str ( i [ 0 ] ) )
2023-10-19 13:25:59 +02:00
categories = " ( " + " , " . join ( catlist ) + " ) "
2023-10-18 17:24:59 +02:00
self . cur . execute ( f """ SELECT ID,NAME,SIZE,IMPORTED FROM Archs
2023-10-19 13:25:59 +02:00
{ " WHERE 1=1 " if category == 0 else " WHERE CATEGORY IN " + categories }
2023-10-18 17:24:59 +02:00
{ keyword_string }
ORDER BY { sorttype } LIMIT { count } ; """ )
2023-10-17 18:25:38 +02:00
archives = self . cur . fetchall ( )
return archives
if __name__ == " __main__ " :
#startup()
db = db ( conn_params )
db . cur . close ( )
db . conn . close ( )
exit ( )