so ich denke das sollte für ne 3 reichen lol

This commit is contained in:
2025-03-29 12:09:11 +01:00
parent 860e4ed063
commit 701cfa7d61
8 changed files with 147 additions and 40 deletions

103
main.py
View File

@@ -1,63 +1,110 @@
from flask import send_file, Flask, request
#from werkzeug.middleware.proxy_fix import ProxyFix # Für Einsatz in Produktion
import sqlite3, hashlib, random, os, pathlib
from flask import send_file, Flask, request, jsonify
#from werkzeug.middleware.proxy_fix import ProxyFix # Für Einsatz in Produktion hinter einem Webserver
import sqlite3, hashlib, random, os, pathlib, jinja2
prefixes = ["B", "KB", "MB", "GB", "TB"]
app = Flask(__name__)
#app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1) # Für Einsatz in Produktion
#app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1) # Für Einsatz in Produktion hinter einem Webserver
db = sqlite3.connect("_map.db", check_same_thread=False)
dbCursor = db.cursor()
dbCursor.execute("CREATE TABLE IF NOT EXISTS _idToFile (id TEXT PRIMARY KEY, destination TEXT, uploadTime DATETIME, fileName TEXT, usesLeft INT);")
jinjaEnv = jinja2.Environment(loader=jinja2.PackageLoader("main", "pages"))
downloadTemplate = jinjaEnv.get_template("download.html")
indexTemplate = jinjaEnv.get_template("index.html")
errorTemplate = jinjaEnv.get_template("error.html")
uploadedTemplate = jinjaEnv.get_template("uploaded.html")
if pathlib.Path("./data").is_dir() == False:
db = sqlite3.connect("_map.db", check_same_thread=False) # Erzeuge oder/und baue eine Verbindung auf zu der Datenbank (check_same_thread muss False sein da Flask mehrere eigene Threads verwendet)
dbCursor = db.cursor() # Keine Ahnung warum explizit ein Zeiger erzeugt werden muss, die meisten der Bibliotheken verwalten das von alleine
dbCursor.execute("CREATE TABLE IF NOT EXISTS _idToFile (id TEXT PRIMARY KEY, destination TEXT, uploadTime DATETIME, fileName TEXT);") # Selbsterklärend
# Erzeuge ein Ordner (falls dieser nicht exisitert) wo die Dateien abgelegt werden
if pathlib.Path("./data").is_dir() == False:
os.mkdir("data")
# Flask dings zeug
@app.route("/")
def mainpage():
return send_file("index.html")
return indexTemplate.render()
@app.route("/upload", methods = ["POST"])
def uploader():
file = request.files['file'] #
name = file.filename.rsplit(".", 1)
file = request.files['file'] # Hole die Datei als FileStorage Objekt
name = file.filename.rsplit(".", 1) #
idValue = ""
idIsUnique = False
while idIsUnique == False:
# Solange die ID nicht eindeutig ist, versuche eine neue zu erzeugen und überprüfe es (wird in 99,99% Fällen nur ein mal durchgelaufen)
while idIsUnique == False:
if idValue != "":
if idValue != "": # Ich könnte das if weglassen aber keine Ahnung ich finde das so besser
idValue = ""
# Fancy weg um eine 14-stellige ID zu erzeugen, wahrscheinlich gibt es fertige Funktionen aber wollte trotzdem eigene haben
for _ in range(14):
vArray = [""] * 3
vArray[0] = chr(random.randint(48, 57)) # 0 - 9
vArray[1] = chr(random.randint(65, 90)) # A - Z
vArray[2] = chr(random.randint(97, 122)) # a - z
vArray = [""] * 3 # Fancy weg um ein Array mit der Länge 3 zu erzeugen
vArray[0] = chr(random.randint(48, 57)) # 0 - 9 in Unicode Charset
vArray[1] = chr(random.randint(65, 90)) # A - Z in Unicode Charset
vArray[2] = chr(random.randint(97, 122)) # a - z in Unicode Charset
selector = random.randint(0,2)
idValue += vArray[selector]
# Aus 3 generierten Werten wähle einen aus und füge es am Ende des Strings an
selector = random.randint(0,2)
idValue += vArray[selector]
dbCursor.execute("SELECT * FROM _idToFile WHERE id=?;", (idValue,))
# Überprüfe ob die erstellte ID bereits existiert, falls ja, dann führe die Schleife nochmal durch
dbCursor.execute("SELECT * FROM _idToFile WHERE id=?;", (idValue,))
if dbCursor.fetchone() == None:
idIsUnique = True
if (len(name) > 1): # Dateinamen die ein Suffix besitzen
path = f"./data/{hashlib.sha256((name[0] + idValue).encode()).hexdigest()}.{name[1]}"
path = f"./data/{hashlib.sha256((name[0] + idValue).encode()).hexdigest()}.{name[1]}" # Wirkt wie schwarze Magie ist aber sehr simpel
else: # Dateinamen die kein Suffix besitzen
path = f"./data/{hashlib.sha256((name[0] + idValue).encode()).hexdigest()}"
file.save(path)
dbCursor.execute("INSERT INTO _idToFile VALUES (?, ?, datetime('now'), ?, ?);", (idValue, path, file.filename, 10))
db.commit()
dbCursor.execute("INSERT INTO _idToFile VALUES (?, ?, datetime('now'), ?);", (idValue, path, file.filename,)) # Füge neuen Eintrag in die Datenbank
db.commit() # Bestätige die Transaktion damit der Eintrag tatsächlich gespeichert wird. Das beste ist ja, dass ich es nur bei INSERT tätigen muss
return "sank you"
if request.user_agent.string != "API":
return uploadedTemplate.render(link=("/file/" + idValue))
else:
return jsonify(status=100,id=idValue)
@app.route("/download/<string:identifier>")
def downloader(identifier):
dbCursor.execute("SELECT destination FROM _idToFile WHERE id=?;", (identifier,))
# Nicht die eleganteste Lösung fürs Download aber ich hab kein Bock es anders zu lösen
# Das hier ist quasi das "Entry Point", es wird eineeine Seite zurück gegeben mit Infos über die Datei sowie einen Download Link
@app.route("/file/<string:identifier>")
def fileInfo(identifier):
dbCursor.execute("SELECT destination, uploadTime, filename FROM _idToFile WHERE id=?;", (identifier,)) # Hole die Infos für die Template
data = dbCursor.fetchone()
if data != None:
sizeBytes = os.path.getsize(data[0])
factor = 0 # 0 -> 1 = Kilo -> 2 = Mega -> 3 = Giga, usw..
while ((sizeBytes / 1024) > 1):
sizeBytes = sizeBytes / 1024
factor += 1
if request.user_agent.string != "API":
return downloadTemplate.render(filename=data[2], uploadDate=data[1], size=("%.2f" % sizeBytes + " " + prefixes[factor]), downloadPath=("/file/" + identifier + "/download"))
else:
return jsonify(status=100, name=data[2], size=("%.2f" % sizeBytes + " " + prefixes[factor]), uploadDate=data[1])
else:
if request.user_agent.string != "API":
return errorTemplate.render(error="keine Datei gefunden")
else:
return jsonify(status=301)
# Das Download Link
@app.route("/file/<string:identifier>/download")
def fileDownload(identifier):
dbCursor.execute("SELECT destination FROM _idToFile WHERE id=?;", (identifier,)) # Das Komma muss so bleiben sonst funktioniert """"prepared statement"""" nicht
path = dbCursor.fetchone()
if path != None:
return send_file(path[0])
else:
return "no file, now fuck off"
if request.user_agent.string != "API":
return errorTemplate.render(error="keine Datei gefunden")
else:
return jsonify(status=301)