diff --git a/code/app.py b/code/app.py index 24ede52..8fbf7da 100644 --- a/code/app.py +++ b/code/app.py @@ -11,7 +11,7 @@ import hashlib import zipfile from revprox import ReverseProxied -__FLEES_VERSION__ = "20180220.0" +__FLEES_VERSION__ = "20180221.0" app = Flask(__name__) app.config.from_object(__name__) # Read config from json ! @@ -100,7 +100,8 @@ def upload(name = None, password = None): ) if get_or_none(share, 'overwrite') == False: if os.path.exists(filename): - return "Overwrite forbidden", 403 + file_versionize(filename) + #~ return "Overwrite forbidden", 403 file.save(filename) set_rights(filename) notify({ @@ -286,6 +287,118 @@ done ) +@app.route('/script/download//', methods=['GET']) +def script_download(name = None, password = None): + session[name] = password + (ok,share) = get_share(name) + if not ok: + return share + files = [] + for file in sorted(os.listdir(share['path'])): + fp = os.path.join(share['path'],file) + if os.path.isdir(fp): + continue + if file.startswith("."): + continue + status = file_stat(fp) + status.update({ + 'token': get_direct_token(share, file) + }) + files.append(status) + script = """#!/bin/bash +test "$1" = "-h" && { + echo "Add argument -f to overwrite files" + exit 0 +} +test "$1" = "-f" && FORCE=1 +which curl &> /dev/null || { + echo "curl required" + exit 1 +} +ROOTURL="%s" +SHARE="%s" +TOKEN="%s" +get_file() { + WRITE=0 + FILENAME="$1" + test "$FORCE" = "1" && WRITE=1 + test -f "${FILENAME}" || WRITE=1 + test "$WRITE" = "1" && { + echo Downloading ${FILENAME} + curl "${ROOTURL}download/${SHARE}/${TOKEN}/${FILENAME}" > "${FILENAME}" + } || { + echo Skipping ${FILENAME} + } +} +"""%( + request.url_root, + name, + password + ) + + for file in files: + script += 'get_file "%s"\n'%( + file['name'], + ) + return script + + +@app.route('/script/direct//', methods=['GET']) +def script_direct(name = None, password = None): + session[name] = password + (ok,share) = get_share(name) + if not ok: + return share + files = [] + for file in sorted(os.listdir(share['path'])): + fp = os.path.join(share['path'],file) + if os.path.isdir(fp): + continue + if file.startswith("."): + continue + status = file_stat(fp) + status.update({ + 'token': get_direct_token(share, file) + }) + files.append(status) + script = """#!/bin/bash +test "$1" = "-h" && { + echo "Add argument -f to overwrite files" + exit 0 +} +test "$1" = "-f" && FORCE=1 +which curl &> /dev/null || { + echo "curl required" + exit 1 +} +ROOTURL="%s" +SHARE="%s" +get_file() { + WRITE=0 + FILENAME="$1" + TOKEN="$2" + test "$FORCE" = "1" && WRITE=1 + test -f "${FILENAME}" || WRITE=1 + test "$WRITE" = "1" && { + echo Downloading ${FILENAME} + curl "${ROOTURL}direct/${SHARE}/${TOKEN}/${FILENAME}" > "${FILENAME}" + } || { + echo Skipping ${FILENAME} + } +} +"""%( + request.url_root, + name, + ) + + for file in files: + script += 'get_file "%s" "%s"\n'%( + file['name'], + file['token'], + ) + return script + + def file_stat(filename): s = os.stat(filename) return { @@ -312,6 +425,20 @@ def file_date_human(num): num ).strftime(app.config['DATE_FORMAT']) +def file_versionize(filename): + """ Move file to old version """ + stats = file_stat(filename) + basename, extension = os.path.splitext(stats['name']) + new_name = os.path.join( + os.path.dirname(filename), + secure_filename("%s.%s%s"%( + basename, + stats['mtime'], + extension + )) + ) + os.rename(filename,new_name) + def get_direct_token(share, filename): if not 'pass_hash' in share: diff --git a/utils/flees-manager.py b/utils/flees-manager.py index cc8d156..207f193 100755 --- a/utils/flees-manager.py +++ b/utils/flees-manager.py @@ -324,6 +324,11 @@ def print_rest_api(shares, config, opts): share['pass_hash'], filename )) + print("or \n\n# curl -s %s/script/download/%s/%s | bash /dev/stdin [-f]"%( + config['public_url'], + share['name'], + share['pass_hash'] + )) elif opts.type == "direct": if 'direct_links' not in share or not share['direct_links']: print("Direct downloading not allowed in this share") @@ -348,6 +353,11 @@ def print_rest_api(shares, config, opts): get_direct_token(share,filename), filename )) + print("or \n\n# curl -s %s/script/direct/%s/%s | bash /dev/stdin [-f]"%( + config['public_url'], + share['name'], + share['pass_hash'] + )) elif opts.type == "zip": print("ZIP download:") print("%s/zip/%s/%s"%( @@ -401,7 +411,7 @@ def parse_options(): parser_add.add_argument('-P','--public', action="store_true", dest="public", default = False) parser_add.add_argument('-u','--upload', action="store_true", dest="upload", default = False) parser_add.add_argument('-o','--overwrite', action="store_false", dest="overwrite", default = True, - help = "Disable file overwrites") + help = "Disable file overwrites. If disabled, old files are versioned with modification date.") parser_add.add_argument('-d','--direct', action="store_true", dest="direct", default = False, help = "Allow direct file sharing (password hash included in URL)") parser_add.add_argument('--pass-plain', action="store_true", dest="plain", default = False, @@ -429,7 +439,7 @@ def parse_options(): parser_modify.add_argument('-P','--public', action="store", dest="public", default = None, choices = ['true','false']) parser_modify.add_argument('-u','--upload', action="store", dest="upload", default = None, choices = ['true','false']) parser_modify.add_argument('-o','--overwrite', action="store", dest="overwrite", default = None, choices = ['true','false'], - help = "Disable file overwrites") + help = "Disable file overwrites. If disabled, old files are versioned with modification date.") parser_modify.add_argument('-d','--direct', action="store", dest="direct_links", default = None, choices = ['true','false'], help = "Allow direct file sharing (password hash included in URL)") parser_modify.add_argument('--pass-plain', action="store_true", dest="plain", default = False,