Files
flees/code/app.py
2018-01-25 13:20:59 +02:00

206 lines
6.0 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os,sys
import json
from datetime import datetime
from flask import Flask, render_template, jsonify, \
redirect, url_for, request, g, session, send_from_directory
from werkzeug.utils import secure_filename
import hashlib
from revprox import ReverseProxied
app = Flask(__name__)
app.config.from_object(__name__)
# Read config from json !
app.config['UPLOAD_FOLDER'] = 'data/'
app.config['SHARES_FILE'] = 'data/shares.json'
app.config['DATE_FORMAT'] = "%Y-%m-%d %H:%M"
app.config['UID'] = 1000
app.secret_key = 'Cz2dw5NiRt3PSMFBSLTAJJi7U2CdW7iPQqEeOaU6'
app.wsgi_app = ReverseProxied(app.wsgi_app)
@app.before_request
def before_request():
g.shares = json.load(open(app.config['SHARES_FILE'],'rt'))
@app.route("/")
def index():
printerr(g.shares)
public_shares = []
for share in g.shares:
public = get_or_none(share,'public')
expired = is_expired(share)
if public and not expired:
public_shares.append({
'name': share['name'],
'expire': get_or_none(share,'expire'),
'upload': get_or_none(share,'upload')
})
return render_template("index.html", entries=public_shares)
@app.route('/authenticate/<name>', methods=['GET','POST'])
def authenticate(name):
if request.method == 'GET':
return render_template('authenticate.html',name=name)
if request.method == 'POST':
user_password = request.form['password'].encode('utf-8')
session[name] = hashlib.sha1(user_password).hexdigest()
return redirect(url_for('list_view',name=name))
@app.route('/upload/<name>/<password>', methods=['POST'])
@app.route('/upload', methods=['POST'])
def upload(name = None, password = None):
if request.method == 'POST':
file = request.files['file']
if name == None:
name = request.form['name']
if password != None:
session[name] = password
(ok,share) = get_share(name)
if not ok:
return share
if file:
filename = os.path.join(
share['path'],
secure_filename(
file.filename
)
)
if get_or_none(share, 'overwrite') == False:
return "Overwrite forbidden", 403
file.save(filename)
os.chown(filename, app.config['UID'], -1)
return redirect(url_for('list_view',name=name))
@app.route('/send/<name>', methods=['GET'])
def send(name):
(ok,share) = get_share(name)
if not ok:
return share
return render_template('send.html',name=name)
@app.route('/list/<name>/<password>', methods=['GET'])
@app.route('/list/<name>', methods=['GET'])
def list_view(name, password = None):
if password != None:
session[name] = password
(ok,share) = get_share(name)
if not ok:
return share
files = []
for file in sorted(os.listdir(share['path'])):
files.append(file_stat(os.path.join(share['path'],file)))
return render_template(
"list.html",
name = share['name'],
entries = files,
public = get_or_none(share,'public'),
upload = get_or_none(share,'upload'),
expire = get_or_none(share,'expire')
)
@app.route('/logout/<name>', methods=['GET'])
def logout(name, password = None):
if name in session:
del session[name]
return render_template(
"logout.html",
name = name
)
@app.route('/download/<name>/<password>/<filename>', methods=['GET'])
@app.route('/download/<name>/<filename>', methods=['GET'])
def download_file(name,filename,password = None):
if password != None:
session[name] = password
(ok,share) = get_share(name)
if not ok:
return share
file_path = os.path.join(share['path'], filename)
if not os.path.exists(file_path):
return 'no such file', 404
return send_from_directory(directory=share['path'], filename=filename)
def file_stat(filename):
s = os.stat(filename)
return {
'size': file_size_human(s.st_size),
'mtime': file_date_human(s.st_mtime),
'name': os.path.basename(filename)
}
def file_size_human(num):
for x in ['&nbsp;B','KB','MB','GB','TB']:
if num < 1024.0:
if x=='&nbsp;B':
return "%d&nbsp;%s" % (num, x)
return "%3.1f&nbsp;%s" % (num, x)
num /= 1024.0
def file_date_human(num):
return datetime.fromtimestamp(
num
).strftime(app.config['DATE_FORMAT'])
def get_or_none(d,key):
if key in d:
return d[key]
else:
return None
def get_share(name):
share = [x for x in g.shares if x['name'] == name]
if len(share) < 1:
return (False,'No such share')
share = share[0]
if is_expired(share):
return (False, 'Share has expired')
authenticated = True
if 'pass_hash' in share:
authenticated = False
if name in session:
if session[name] == share['pass_hash']:
authenticated = True
if 'pass_plain' in share:
authenticated = False
if name in session:
if session[name] == hashlib.sha1(share['pass_plain'].encode('utf-8')).hexdigest():
authenticated = True
if not authenticated:
return (False,redirect(url_for('authenticate',name=name)))
if not 'path' in share:
return (False,'no path defined')
share.update({
"path": os.path.join(
app.config['UPLOAD_FOLDER'],
share['path']
)
})
if not os.path.exists(share['path']):
os.makedirs(share['path'])
os.chown(share['path'], app.config['UID'], -1)
return (True,share)
def is_expired(share):
expires = get_or_none(share, 'expire')
if expires:
if datetime.now() > datetime.strptime(expires, app.config['DATE_FORMAT']):
return True
return False
def printerr(s):
sys.stderr.write(str(s)+"\n")
sys.stderr.flush()
if __name__ == "__main__":
app.run(debug=True)