Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
Dendy | 4e4048561f |
|
@ -1,9 +1,6 @@
|
|||
name = "Folder share"
|
||||
base_path = "/path/to/folder"
|
||||
favicon = "/.favicon.png"
|
||||
#password = "publicpass"
|
||||
admin_password = "verysecurepass"
|
||||
#footer = "Something something, made with love or whatever"
|
||||
|
||||
[qbittorrent]
|
||||
base_url = "http://127.0.0.1:8080"
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
from flask import Flask, Response, render_template, send_file, request
|
||||
from flask import Flask, render_template, send_file, request
|
||||
|
||||
from . import file
|
||||
from . import config
|
||||
from . import auth
|
||||
|
||||
app = Flask(
|
||||
__name__,
|
||||
|
@ -22,7 +23,6 @@ app.jinja_env.globals.update(
|
|||
|
||||
@app.route('/', defaults={'path': ''})
|
||||
@app.route('/<path:path>')
|
||||
@auth.requires_auth
|
||||
def index(path):
|
||||
internal_path = os.path.join(config.get('base_path'), path)
|
||||
path = '/' + path
|
||||
|
@ -55,7 +55,6 @@ def index(path):
|
|||
path=path,
|
||||
dirs=dirs,
|
||||
files=files,
|
||||
footer=config.get("footer"),
|
||||
),
|
||||
200,
|
||||
)
|
||||
|
@ -64,8 +63,58 @@ def index(path):
|
|||
return send_file(internal_path)
|
||||
|
||||
|
||||
@app.route('/mass_download')
|
||||
def mass_download():
|
||||
internal_base = config.get('base_path')
|
||||
|
||||
base = request.args.get('base', '')
|
||||
files = request.args.getlist('file')
|
||||
|
||||
# Checks ###################################################
|
||||
|
||||
if base == '':
|
||||
return {"error": "Base path not supplied"}, 400
|
||||
|
||||
if '..' in base or base[0] != '/':
|
||||
return {"error": "Invalid base path"}, 400
|
||||
|
||||
# TODO: If it's 1 file and it's not a directory, then redirect to the file
|
||||
if len(files) < 1:
|
||||
return {"error": "A minimum of two files is required"}, 400
|
||||
|
||||
# TODO: Check if the files exist
|
||||
# TODO: Check if the files are bigger than a certain amount?
|
||||
|
||||
# Actual serving ###########################################
|
||||
|
||||
for i_file in files:
|
||||
internal_path = os.path.join(internal_base, base[1:], i_file)
|
||||
|
||||
# FIXME: I'm broke
|
||||
if os.path.isdir(internal_path):
|
||||
for root, _, subfiles in os.walk(internal_path):
|
||||
for i_subfile in subfiles:
|
||||
external_root = root[len(internal_base) + 1:]
|
||||
print(external_root)
|
||||
files.append(os.path.join(root, external_root))
|
||||
print(files)
|
||||
|
||||
with zipfile.ZipFile('/tmp/download.zip', 'w') as f_zip:
|
||||
for i_file in files:
|
||||
internal_path = os.path.join(internal_base, base[1:], i_file)
|
||||
|
||||
# print(internal_path)
|
||||
|
||||
if not os.path.exists(internal_path):
|
||||
# And what is this?¿
|
||||
return {'error': f'The following path does not exist: "{i_file}"'}, 400
|
||||
|
||||
f_zip.write(internal_path)
|
||||
|
||||
return [base, files], 200
|
||||
|
||||
|
||||
@app.route('/search')
|
||||
@auth.requires_auth
|
||||
def search():
|
||||
q = request.args.get('q', '')
|
||||
|
||||
|
@ -75,7 +124,6 @@ def search():
|
|||
"error.html",
|
||||
code=400,
|
||||
msg='No search string provided.',
|
||||
footer=config.get('footer'),
|
||||
),
|
||||
400,
|
||||
)
|
||||
|
@ -90,27 +138,3 @@ def search():
|
|||
),
|
||||
200,
|
||||
)
|
||||
|
||||
|
||||
@app.route('/auth', methods=['POST'])
|
||||
def auth_handle():
|
||||
expected_pass = config.get('password')
|
||||
|
||||
if expected_pass is None:
|
||||
return "You shouldn't be here.", 405
|
||||
|
||||
if request.form.get("pass", None) != expected_pass:
|
||||
return render_template(
|
||||
'auth.html',
|
||||
path=request.form.get("location", "/"),
|
||||
error_msg="Incorrect password",
|
||||
), 403
|
||||
|
||||
return Response(
|
||||
"Redirecting...",
|
||||
303,
|
||||
{
|
||||
'Location': request.form.get("location", "/"),
|
||||
'Set-Cookie': 'film_session=To be changed',
|
||||
}
|
||||
)
|
||||
|
|
31
src/auth.py
31
src/auth.py
|
@ -1,31 +0,0 @@
|
|||
from functools import wraps
|
||||
|
||||
from flask import request, render_template
|
||||
from . import config
|
||||
|
||||
# FIXME: EVERYTHING is under the auth now, even files (makes sense)
|
||||
# but that means that even the favicon requires authentication.
|
||||
|
||||
|
||||
def auth_page(*args, **kwargs):
|
||||
# TODO: Is there a better way of doing this?
|
||||
path = f"{request.path}?{request.query_string.decode('utf-8')}"
|
||||
|
||||
return render_template("auth.html", path=path), 403
|
||||
|
||||
|
||||
def requires_auth(f):
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
if config.get('password') in [False, None, ""]:
|
||||
return f(*args, **kwargs)
|
||||
|
||||
if request.cookies.get('film_session', None) != 'To be changed':
|
||||
# Not authenticated
|
||||
return auth_page()
|
||||
|
||||
# User properly authenticated
|
||||
print(request.cookies['film_session'])
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return decorated
|
|
@ -1,12 +1,7 @@
|
|||
html {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #191919;
|
||||
color: white;
|
||||
font-family: monospace;
|
||||
margin-bottom: 100px;
|
||||
background-color: #191919;
|
||||
color: white;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
a {
|
||||
|
@ -23,17 +18,6 @@ input {
|
|||
background-color: white;
|
||||
}
|
||||
|
||||
footer {
|
||||
background-color: black;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: calc(100vw - 20px);
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.base_path {
|
||||
color: grey;
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Secret required{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>Secret required</h1>
|
||||
<form method="POST" action="/auth">
|
||||
<input type="hidden" name="location" value="{{ path }}">
|
||||
<input type="text" name="pass" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
<p style="color:red;">{{ error_msg|default('') }}</p>
|
||||
{% endblock %}
|
|
@ -11,11 +11,17 @@
|
|||
<br />
|
||||
|
||||
{% if path != "/" %}
|
||||
<a href="../"><--</a>
|
||||
<a href="."><--</a>
|
||||
<br /><br />
|
||||
{% endif %}
|
||||
|
||||
<form action="/mass_download" method="GET" id="mass_form">
|
||||
<input type="submit" value="Download" />
|
||||
<input type="hidden" name="base" value="{{ path }}" >
|
||||
</form>
|
||||
|
||||
{% for dir in dirs %}
|
||||
<input type="checkbox" name="file" value="{{ dir }}" form="mass_form"/>
|
||||
<a href="{{ path_join(path, dir) }}">{{ dir }}</a><br />
|
||||
{% endfor %}
|
||||
|
||||
|
@ -26,13 +32,8 @@
|
|||
{% endif %}
|
||||
|
||||
{% for file in files %}
|
||||
<input type="checkbox" name="file" value="{{ file }}" form="mass_form"/>
|
||||
<a href="{{ path_join(path, file) }}">{{ file }}</a><br />
|
||||
{% endfor %}
|
||||
|
||||
{% if footer not in [None, False, ""] %}
|
||||
<footer>
|
||||
{{ footer }}
|
||||
</footer>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in New Issue