aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
Diffstat (limited to 'backend')
-rw-r--r--backend/main.py43
-rw-r--r--backend/utils.py55
2 files changed, 66 insertions, 32 deletions
diff --git a/backend/main.py b/backend/main.py
index 2156d0e..baf8b1d 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -4,24 +4,14 @@ import cgi
import os
import sqlite3
import mimetypes
+import urllib.parse
import Admin
-from utils import redirect
+import utils
def playout(filename, content = "text/html"):
return ["", [('Content-Type', content if content else "application/octet-stream"), ("X-Accel-Redirect", filename)], None]
-def target_filename_internal(alias, filename):
- target = alias["path"] + "/"
- if filename:
- target += filename
- if config.user_subdirs:
- target = alias["user"] + "/" + target
- return target
-
-def target_filename(alias, file):
- return config.fileroot + target_filename_internal(alias, file)
-
def resolve_alias(alias):
resolved = None
db = sqlite3.connect(config.database, check_same_thread = False)
@@ -38,16 +28,12 @@ def resolve_alias(alias):
def listing(alias):
listing = {"total": 0, "files": [], "access": alias["access"], "display": alias["display"]}
- # TODO make sorting configurable
if 'r' in alias["access"]:
- directory = target_filename(alias, None)
- files = sorted(os.listdir(directory))
-
- for filename in files:
- if os.path.isfile(directory + filename):
- size = os.path.getsize(directory + filename)
- listing["files"].append({"name": filename, "size": size})
- listing["total"] += size
+ directory = utils.target_filename(alias, None)
+ listing["files"] = utils.dirlisting(directory, True, False)
+ # Calculate total size
+ for file in listing["files"]:
+ listing["total"] += file["size"]
return [json.dumps(listing), [('Content-Type','application/json')], "200 OK"]
@@ -55,7 +41,7 @@ def upload(alias, post):
if 'c' not in alias["access"]:
return ["", [('Content-Type','text/html')], "403 No"]
if post["file"].filename:
- target = target_filename(alias, os.path.basename(post["file"].filename))
+ target = utils.target_filename(alias, utils.sanitize_filename(post["file"].filename))
while os.path.isfile(target):
target += "_dup"
@@ -85,11 +71,11 @@ def route(path, env, post):
alias = resolve_alias(path[0])
if not alias:
- return redirect(config.homepage)
+ return utils.redirect(config.homepage)
# Redirect if no slash after alias
if len(path) == 1:
- return redirect(path[0] + "/");
+ return utils.redirect(path[0] + "/");
if len(path) > 1 and path[1] == "upload":
return upload(alias, post)
@@ -98,11 +84,12 @@ def route(path, env, post):
return listing(alias)
if len(path) > 1 and path[1] == "file":
- print("/data/" + target_filename_internal(alias, path[2]))
- return playout("/data/" + target_filename_internal(alias, path[2]), mimetypes.guess_type(path[2])[0])
+ filename = utils.sanitize_filename(path[2])
+ return playout("/data/" + utils.target_filename_internal(alias, filename), mimetypes.guess_type(filename)[0])
if len(path) > 1 and path[1] == "preview" and alias["display"] == "gallery":
- return playout("/data/" + target_filename_internal(alias, "preview/" + path[2]), mimetypes.guess_type(path[2])[0])
+ filename = utils.sanitize_filename(path[2])
+ return playout("/data/" + utils.target_filename_internal(alias, "preview/" + filename), mimetypes.guess_type(filename)[0])
return playout("/interface/listing.htm")
@@ -118,7 +105,7 @@ def handle_request(env, response):
else:
content_length = int(env.get('CONTENT_LENGTH', '0'))
post_raw = env["wsgi.input"].read(content_length).decode('utf-8')
- post = post_raw
+ post = urllib.parse.parse_qs(post_raw)
except ValueError as e:
post = None
diff --git a/backend/utils.py b/backend/utils.py
index ddb0adc..bab7ebe 100644
--- a/backend/utils.py
+++ b/backend/utils.py
@@ -1,12 +1,59 @@
+import sqlite3
+import os
+
import config
+db = sqlite3.connect(config.database, check_same_thread = False)
+
def redirect(target):
return ["", [('Content-Type','text/html'), ("Location", target)], "302 Redirect"]
def ensure_user(name):
- # TODO
+ # Add a user directory if configured
+ if config.user_subdirs:
+ try:
+ os.mkdir(config.fileroot + name)
+ except FileExistsError:
+ pass
+
+ # Add the user to the database
+ db.cursor().execute("INSERT OR IGNORE INTO users (name) VALUES (:user)", {"user": name})
+ db.commit()
return
-def is_user(name):
- # TODO
- return False
+def userdir(name):
+ rootdir = config.fileroot
+ if config.user_subdirs:
+ rootdir += name + "/"
+ return rootdir
+
+def sanitize_filename(input):
+ filename = "".join(filter(lambda c: c not in "<>&", os.path.basename(input)))
+ # os.path.basename still allows `..` as basename
+ if not filename or filename.startswith("."):
+ raise ValueError("Invalid filename supplied: " + filename)
+ return filename
+
+def target_filename_internal(alias, filename):
+ target = alias["path"] + "/"
+ if filename:
+ target += filename
+ if config.user_subdirs:
+ target = alias["user"] + "/" + target
+ return target
+
+def target_filename(alias, file):
+ return config.fileroot + target_filename_internal(alias, file)
+
+def dirlisting(path, files, dirs):
+ listing = []
+ entries = sorted(os.listdir(path))
+
+ for entry in entries:
+ if dirs and os.path.isdir(path + entry):
+ listing.append({"name": entry})
+ if files and os.path.isfile(path + entry):
+ size = os.path.getsize(path + entry)
+ listing.append({"name": entry, "size": size})
+
+ return listing