css tuning. disallow too large zips
This commit is contained in:
40
code/app.py
40
code/app.py
@@ -18,6 +18,7 @@ config_values = json.load(open(os.getenv('FLEES_CONFIG'),'rt'))
|
|||||||
app.config['UPLOAD_FOLDER'] = config_values['data_folder']
|
app.config['UPLOAD_FOLDER'] = config_values['data_folder']
|
||||||
app.config['SHARES_FILE'] = config_values['shares_file']
|
app.config['SHARES_FILE'] = config_values['shares_file']
|
||||||
app.config['ZIP_FOLDER'] = config_values['zip_folder']
|
app.config['ZIP_FOLDER'] = config_values['zip_folder']
|
||||||
|
app.config['MAX_ZIP_SIZE'] = config_values['max_zip_size'] # megabytes
|
||||||
app.config['DATE_FORMAT'] = config_values['date_format']
|
app.config['DATE_FORMAT'] = config_values['date_format']
|
||||||
app.config['UID'] = config_values['uid']
|
app.config['UID'] = config_values['uid']
|
||||||
app.config['DEBUG'] = config_values['debug']
|
app.config['DEBUG'] = config_values['debug']
|
||||||
@@ -102,7 +103,10 @@ def list_view(name, password = None):
|
|||||||
return share
|
return share
|
||||||
files = []
|
files = []
|
||||||
for file in sorted(os.listdir(share['path'])):
|
for file in sorted(os.listdir(share['path'])):
|
||||||
status = file_stat(os.path.join(share['path'],file))
|
fp = os.path.join(share['path'],file)
|
||||||
|
if os.path.isdir(fp):
|
||||||
|
continue
|
||||||
|
status = file_stat(fp)
|
||||||
status.update({
|
status.update({
|
||||||
'token': get_direct_token(share, file)
|
'token': get_direct_token(share, file)
|
||||||
})
|
})
|
||||||
@@ -173,10 +177,13 @@ def download_zip(name,password = None):
|
|||||||
(ok,share) = get_share(name)
|
(ok,share) = get_share(name)
|
||||||
if not ok:
|
if not ok:
|
||||||
return share
|
return share
|
||||||
|
folder_size = get_folder_size(share['path'])
|
||||||
|
if folder_size/(1024*1024) > app.config['MAX_ZIP_SIZE']:
|
||||||
|
return "Maximum ZIP size exceeded", 400
|
||||||
zip_clean()
|
zip_clean()
|
||||||
zip_path = zip_share(share)
|
zip_path = zip_share(share)
|
||||||
return send_file(
|
return send_file(
|
||||||
zip_path,
|
zip_path,
|
||||||
as_attachment = True,
|
as_attachment = True,
|
||||||
attachment_filename = name + ".zip"
|
attachment_filename = name + ".zip"
|
||||||
)
|
)
|
||||||
@@ -216,6 +223,18 @@ def get_direct_token(share, filename):
|
|||||||
share['pass_hash'].encode('utf-8') + filename.encode('utf-8')
|
share['pass_hash'].encode('utf-8') + filename.encode('utf-8')
|
||||||
).hexdigest()
|
).hexdigest()
|
||||||
|
|
||||||
|
def get_folder_size(path):
|
||||||
|
|
||||||
|
total_size = 0
|
||||||
|
for filename in os.listdir(path):
|
||||||
|
fp = os.path.join(path, filename)
|
||||||
|
if os.path.isdir(fp):
|
||||||
|
continue
|
||||||
|
total_size += os.path.getsize(
|
||||||
|
fp
|
||||||
|
)
|
||||||
|
return total_size
|
||||||
|
|
||||||
|
|
||||||
def get_or_none(d,key):
|
def get_or_none(d,key):
|
||||||
if key in d:
|
if key in d:
|
||||||
@@ -227,7 +246,7 @@ def get_or_none(d,key):
|
|||||||
def get_share(name, require_auth = True):
|
def get_share(name, require_auth = True):
|
||||||
share = [x for x in g.shares if x['name'] == name]
|
share = [x for x in g.shares if x['name'] == name]
|
||||||
if len(share) < 1:
|
if len(share) < 1:
|
||||||
return (False,'No such share')
|
return (False,redirect(url_for('authenticate',name=name)))
|
||||||
share = share[0]
|
share = share[0]
|
||||||
if is_expired(share):
|
if is_expired(share):
|
||||||
return (False, 'Share has expired')
|
return (False, 'Share has expired')
|
||||||
@@ -274,23 +293,26 @@ def print_debug(s):
|
|||||||
|
|
||||||
|
|
||||||
def zip_share(share):
|
def zip_share(share):
|
||||||
|
|
||||||
if not os.path.exists(app.config['ZIP_FOLDER']):
|
if not os.path.exists(app.config['ZIP_FOLDER']):
|
||||||
os.makedirs(app.config['ZIP_FOLDER'])
|
os.makedirs(app.config['ZIP_FOLDER'])
|
||||||
os.chown(app.config['ZIP_FOLDER'], app.config['UID'], -1)
|
os.chown(app.config['ZIP_FOLDER'], app.config['UID'], -1)
|
||||||
|
|
||||||
zip_path = os.path.join(
|
zip_path = os.path.join(
|
||||||
app.config['ZIP_FOLDER'],
|
app.config['ZIP_FOLDER'],
|
||||||
"%s-%d.zip"%(
|
"%s-%d.zip"%(
|
||||||
share['name'],
|
share['name'],
|
||||||
time.time()
|
time.time()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
zf = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED)
|
zf = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED)
|
||||||
for file in sorted(os.listdir(share['path'])):
|
for file in sorted(os.listdir(share['path'])):
|
||||||
print_debug(os.path.join(share['path'],file))
|
fp = os.path.join(share['path'], file)
|
||||||
|
if os.path.isdir(fp):
|
||||||
|
continue
|
||||||
|
print_debug(fp)
|
||||||
zf.write(
|
zf.write(
|
||||||
os.path.join(share['path'],file),
|
fp,
|
||||||
arcname = os.path.join(share['name'],file)
|
arcname = os.path.join(share['name'],file)
|
||||||
)
|
)
|
||||||
zf.close()
|
zf.close()
|
||||||
@@ -309,7 +331,7 @@ def zip_clean():
|
|||||||
).st_mtime
|
).st_mtime
|
||||||
if mtime + 3600 < time.time():
|
if mtime + 3600 < time.time():
|
||||||
os.remove(os.path.join(app.config['ZIP_FOLDER'],file))
|
os.remove(os.path.join(app.config['ZIP_FOLDER'],file))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(debug=True)
|
app.run(debug=True)
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ a:link {
|
|||||||
#footer {
|
#footer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
left: 9vw;
|
||||||
width: 80vw;
|
width: 80vw;
|
||||||
height: 23px;
|
height: 23px;
|
||||||
background: #f3f3fb;
|
background: #f3f3fb;
|
||||||
@@ -63,16 +64,29 @@ tr:nth-child(even) {
|
|||||||
border: 4px solid lightslategray;
|
border: 4px solid lightslategray;
|
||||||
background-color: #f3f3fb;
|
background-color: #f3f3fb;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#list_menu ul {
|
#list_menu ul {
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
#list_upload {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
#list_upload_select {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
#list_upload_button {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#list_table {
|
#list_table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin-left: 2em;
|
margin-left: 2em;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
|
margin-bottom: 33px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.direct {
|
.direct {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<div id=list_upload>
|
<div id=list_upload>
|
||||||
<form action={{ url_for('upload') }} method=post enctype=multipart/form-data>
|
<form action={{ url_for('upload') }} method=post enctype=multipart/form-data>
|
||||||
<input type=hidden name=name value="{{ name|safe }}" />
|
<input type=hidden name=name value="{{ name|safe }}" />
|
||||||
<input type=file name=file onchange="document.getElementById('list_upload_button').disabled = false;">
|
<input id="list_upload_select" type=file name=file onchange="document.getElementById('list_upload_button').disabled = false;"><br>
|
||||||
<input id="list_upload_button" type=submit value=Upload disabled>
|
<input id="list_upload_button" type=submit value=Upload disabled>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
"__comment": [
|
"__comment": [
|
||||||
"workers: number of parallel processes. single long upload reserves a process.",
|
"workers: number of parallel processes. single long upload reserves a process.",
|
||||||
"timeout: seconds for process to last. single long upload cant take longer than this.",
|
"timeout: seconds for process to last. single long upload cant take longer than this.",
|
||||||
"uid: Docker runs as root, this changes owner of written files. -1 to skip chowning"
|
"uid: Docker runs as root, this changes owner of written files. -1 to skip chowning",
|
||||||
|
"max_zip_size: dont allow zip downloads if folder size exceeds this many megabytes"
|
||||||
],
|
],
|
||||||
"workers": 8,
|
"workers": 8,
|
||||||
"timeout": 3600,
|
"timeout": 3600,
|
||||||
@@ -11,6 +12,7 @@
|
|||||||
"data_folder": "data",
|
"data_folder": "data",
|
||||||
"shares_file": "data/shares.json",
|
"shares_file": "data/shares.json",
|
||||||
"zip_folder": "data/.zip",
|
"zip_folder": "data/.zip",
|
||||||
|
"max_zip_size": 1000,
|
||||||
"date_format": "%Y-%m-%d %H:%M",
|
"date_format": "%Y-%m-%d %H:%M",
|
||||||
"debug": false
|
"debug": false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user