diff --git a/.gitignore b/.gitignore index 5486276..bb179fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ __pycache__/ -*/__pycache__/ secret_key *.db - +*.swp diff --git a/fileHost.py b/fileHost.py index 1af19a0..32acfd6 100755 --- a/fileHost.py +++ b/fileHost.py @@ -3,11 +3,13 @@ Simple file host using Flask. """ import os +import re import time import atexit import string import secrets import sqlite3 +import tempfile import functools import threading from datetime import datetime @@ -16,12 +18,14 @@ from passlib.hash import argon2 from flask import Flask, session, request, abort, redirect, url_for, g, \ render_template from werkzeug.utils import secure_filename +from werkzeug.datastructures import FileStorage from flask_paranoid import Paranoid from apscheduler.schedulers.background import BackgroundScheduler +import requests app = Flask(__name__) app.config['MAX_CONTENT_LENGTH'] = 128 * 1024 * 1024 -app.config["UPLOAD_DIR"] = "/usr/local/www/html/up" +app.config["UPLOAD_DIR"] = "/var/www/html/up" app.config["UPLOAD_URL"] = "https://steelbea.me/up/" app.config["DB_NAME"] = "fileHost.db" app.config["DB_LOCK"] = threading.Lock() @@ -153,7 +157,7 @@ def delete_file(filename): def login_required(url=None): """ A decorator function to protect certain endpoints by requiring the user - to either pass a valid session cookie, or pass thier username and + to either pass a valid session cookie, or pass their username and password along with the request to login. """ def actual_decorator(func): @@ -334,10 +338,17 @@ def upload(): Saves the uploaded files and returns URLs pointing to them. """ username = session.get("username") - if not username: - username = request.form.get("user") + + if request.form.get("url"): + try: + f = [download_file(request.form.get("url"))] + except ValueError as e: + return e + else: + f = [] + urls = [] - for file in request.files.getlist("files"): + for file in request.files.getlist("files") + f: fname = secure_filename(file.filename) pre = get_rand_chars(8) fdir = app.config.get("UPLOAD_DIR") @@ -397,6 +408,40 @@ def get_rand_chars(n): return "".join(chars) +def download_file(url): + """ + Downloads the file at the given url while observing file size and + timeout limitations. + """ + timeout = 10 + requests_kwargs = { + 'stream': True, + 'headers': {'User-Agent': "Steelbea.me LTD needs YOUR files."}, + 'timeout': timeout, + 'verify': True + } + t = tempfile.TemporaryFile() + with requests.get(url, **requests_kwargs) as r: + size = 0 + start_time = time.time() + for chunk in r.iter_content(102400): + if time.time() - start_time > timeout: + raise ValueError('timeout reached') + + size += len(chunk) + if size > app.config['MAX_CONTENT_LENGTH']: + raise ValueError('response too large') + t.write(chunk) + if r.headers.get('Content-Disposition'): + fname = re.search(r'filename="(.+)"', + r.headers['content-disposition']) + else: + fname = os.path.basename(url) + t.seek(0) + f = FileStorage(stream=t, filename=fname, name='url') + return f + + init() atexit.register(scheduler.shutdown) if __name__ == "__main__": diff --git a/templates/index.html b/templates/index.html index a4f2cc2..1c1b467 100644 --- a/templates/index.html +++ b/templates/index.html @@ -4,23 +4,24 @@