diff --git a/code/app.py b/code/app.py index ac7b7ce..a05a4ce 100644 --- a/code/app.py +++ b/code/app.py @@ -12,8 +12,12 @@ 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) @@ -27,7 +31,8 @@ def index(): public_shares = [] for share in g.shares: public = get_or_none(share,'public') - if public: + expired = is_expired(share) + if public and not expired: public_shares.append({ 'name': share['name'], 'expire': get_or_none(share,'expire'), @@ -61,6 +66,7 @@ def upload(): ) ) file.save(filename) + os.chown(filename, app.config['UID'], -1) return redirect(url_for('list_view',name=name)) @app.route('/send/', methods=['GET']) @@ -78,7 +84,14 @@ def list_view(name): 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) + 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') + ) #~ return jsonify({"share":share, "files": files}) @app.route('/download//', methods=['GET']) @@ -94,11 +107,27 @@ def download_file(name,filename): def file_stat(filename): s = os.stat(filename) return { - 'size': s.st_size, - 'mtime': s.st_mtime, + '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 [' B','KB','MB','GB','TB']: + if num < 1024.0: + if x==' B': + return "%d %s" % (num, x) + return "%3.1f %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] @@ -110,6 +139,8 @@ def get_share(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 @@ -132,8 +163,16 @@ def get_share(name): }) 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() diff --git a/code/templates/list.html b/code/templates/list.html index 59501d6..dc56ed7 100644 --- a/code/templates/list.html +++ b/code/templates/list.html @@ -1,22 +1,36 @@ {% extends "layout.html" %} {% block body %} +

{{ name }}

+ {% if upload %} + upload + {% else %} + Grayed out + upload + {% endif %} +
+ {% if public %} + Share is public + {% else %} + Share is private + {% endif %} +
+ {% if expire %} + Share expires {{ expire }} + {% else %} + Share never expires + {% endif %} +
+ {% for entry in entries %} -
name - time - trip - kmδ - daysδ - km/d + size + mtime
{{ entry.name }} + {{ entry.name }} {{ entry.size|safe }} {{ entry.mtime|safe }} - {% else %} -
  • no files {% endfor %}
  • {% endblock %} diff --git a/data/shares.json.example b/data/shares.json.example new file mode 100644 index 0000000..af6ccd2 --- /dev/null +++ b/data/shares.json.example @@ -0,0 +1,19 @@ +[ +{ + "name": "test", + "path": "files", + "pass_hash": "86d2db203591135ea63473e49759a1d2e43fdc4d9857aeee642713c4e837be12", + "pass_plain": "tissit", + "upload": true, + "public": false, + "expire": "2018-02-28 10:30" +}, +{ + "name": "foo", + "path": "foo", + "pass_hash": "86d2db203591135ea63473e49759a1d2e43fdc4d9857aeee642713c4e837be12", + "pass_plain": "tissit", + "upload": false, + "public": true +} +] diff --git a/utils/share_template.py b/utils/share_template.py new file mode 100755 index 0000000..6e32ed2 --- /dev/null +++ b/utils/share_template.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +import hashlib,argparse,json,sys +from datetime import datetime +parser = argparse.ArgumentParser(description='Flees share template generator') + +parser.add_argument('-n','--name', action="store", dest="name", required = True) +parser.add_argument('-p','--path', action="store", dest="path", required = True,help= "path relative to data folder") +parser.add_argument('-P','--public', action="store_true", dest="public", default = False) +parser.add_argument('-u','--upload', action="store_true", dest="upload", default = False) +parser.add_argument('--pass-plain', action="store", dest="plain", default = False) +parser.add_argument('--pass-hashed', action="store", dest="hashed", default = False) +parser.add_argument('-e','--expire', action="store", dest="expire", default = False, help = "expire date in format 2018-12-24 21:00") + +opts = parser.parse_args() + +share = { + 'name': opts.name, + 'path': opts.path, + 'public': opts.public, + 'upload': opts.upload, +} +if opts.plain: + share.update({ + 'pass_plain': opts.plain + }) +if opts.hashed: + share.update({ + 'pass_hash': hashlib.sha256(opts.hashed).hexdigest() + }) +if opts.expire: + try: + date_object = datetime.strptime(opts.expire,"%Y-%m-%d %H:%M") + except ValueError as e: + print(e) + sys.exit(1) + share.update({ + 'expire': opts.expire + }) + + +print(json.dumps(share, indent = 2)) + +