big rewrite of token system
This commit is contained in:
147
code/app.py
147
code/app.py
@@ -11,8 +11,10 @@ import hashlib
|
||||
import zipfile
|
||||
from multiprocessing import Process
|
||||
from revprox import ReverseProxied
|
||||
from utils.utils import *
|
||||
from utils.crypt import *
|
||||
|
||||
__FLEES_VERSION__ = "20180224.0b"
|
||||
__FLEES_VERSION__ = "20180225.0"
|
||||
app = Flask(__name__)
|
||||
app.config.from_object(__name__)
|
||||
# Read config from json !
|
||||
@@ -39,6 +41,7 @@ if 'notifier' in config_values:
|
||||
|
||||
app.secret_key = config_values['app_secret_key']
|
||||
app.wsgi_app = ReverseProxied(app.wsgi_app)
|
||||
app.config['CRYPTO'] = Crypto(app.secret_key)
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
@@ -51,7 +54,7 @@ def before_request():
|
||||
def index():
|
||||
public_shares = []
|
||||
for share in g.shares:
|
||||
public = get_or_none(share,'public')
|
||||
public = get_or_none('public', share)
|
||||
expired = is_expired(share)
|
||||
authenticated_share = get_share(share['name'])
|
||||
password_set = False
|
||||
@@ -61,10 +64,10 @@ def index():
|
||||
if public or password_set:
|
||||
public_shares.append({
|
||||
'name': share['name'],
|
||||
'expire': get_or_none(share,'expire'),
|
||||
'upload': get_or_none(share,'upload'),
|
||||
'expire': get_or_none('expire', share),
|
||||
'upload': get_or_none('upload', share),
|
||||
'password_set': password_set,
|
||||
'description': get_or_none(share,'description','')
|
||||
'description': get_or_none('description', share, '')
|
||||
})
|
||||
|
||||
return render_template("index.html", entries=public_shares)
|
||||
@@ -75,7 +78,7 @@ def authenticate(name):
|
||||
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()
|
||||
session[name] = password_hash(user_password)
|
||||
return redirect(url_for('list_view',name=name))
|
||||
|
||||
@app.route('/upload/<name>/<password>', methods=['POST'])
|
||||
@@ -86,11 +89,11 @@ def upload(name = None, password = None):
|
||||
if name == None:
|
||||
name = request.form['name']
|
||||
if password != None:
|
||||
session[name] = password
|
||||
session[name] = app.config['CRYPTO'].decrypt(password)
|
||||
(ok,share) = get_share(name)
|
||||
if not ok:
|
||||
return share
|
||||
if not get_or_none(share,'upload') == True:
|
||||
if not get_or_none('upload', share) == True:
|
||||
return "Upload not allowed\n",400
|
||||
if file:
|
||||
filename = os.path.join(
|
||||
@@ -99,14 +102,14 @@ def upload(name = None, password = None):
|
||||
file.filename
|
||||
)
|
||||
)
|
||||
if get_or_none(share, 'overwrite') == False:
|
||||
if get_or_none('overwrite', share) == False:
|
||||
if os.path.exists(filename):
|
||||
file_versionize(filename)
|
||||
#~ return "Overwrite forbidden", 403
|
||||
file.save(filename)
|
||||
set_rights(filename)
|
||||
notify({
|
||||
"recipient": get_or_none(share,'recipient'),
|
||||
"recipient": get_or_none('recipient', share),
|
||||
"share": name,
|
||||
"filename": filename,
|
||||
"operation": "upload"
|
||||
@@ -122,11 +125,11 @@ def upload(name = None, password = None):
|
||||
@app.route('/upload_join/<name>/<password>', methods=['POST'])
|
||||
def upload_join_splitted(name, password):
|
||||
if request.method == 'POST':
|
||||
session[name] = password
|
||||
session[name] = app.config['CRYPTO'].decrypt(password)
|
||||
(ok,share) = get_share(name)
|
||||
if not ok:
|
||||
return share
|
||||
if not get_or_none(share,'upload') == True:
|
||||
if not get_or_none('upload', share) == True:
|
||||
return "Upload not allowed",400
|
||||
if not 'filename' in request.form:
|
||||
return "No filename given", 400
|
||||
@@ -150,7 +153,7 @@ def upload_join_splitted(name, password):
|
||||
share['path'],
|
||||
request.form['filename']
|
||||
)
|
||||
if get_or_none(share, 'overwrite') == False:
|
||||
if get_or_none('overwrite', share) == False:
|
||||
if os.path.exists(target_name):
|
||||
file_versionize(target_name)
|
||||
|
||||
@@ -175,7 +178,8 @@ def send(name):
|
||||
@app.route('/list/<name>', methods=['GET'])
|
||||
def list_view(name, password = None):
|
||||
if password != None:
|
||||
session[name] = password
|
||||
session[name] = app.config['CRYPTO'].decrypt(password)
|
||||
return redirect(url_for('list_view',name=name))
|
||||
(ok,share) = get_share(name)
|
||||
if not ok:
|
||||
return share
|
||||
@@ -192,22 +196,26 @@ def list_view(name, password = None):
|
||||
})
|
||||
files.append(status)
|
||||
# direct share links not allowed if password isnt set
|
||||
allow_direct = get_or_none(share,'direct_links') if get_or_none(share,'pass_hash') else False
|
||||
allow_direct = get_or_none('direct_links', share) if get_or_none('pass_hash', share) else False
|
||||
upload = get_or_none('upload', share)
|
||||
overwrite = get_or_none('overwrite', share)
|
||||
if not upload:
|
||||
overwrite = False
|
||||
return render_template(
|
||||
"list.html",
|
||||
name = share['name'],
|
||||
entries = files,
|
||||
password = get_or_none(share,'pass_hash'),
|
||||
public = get_or_none(share,'public'),
|
||||
upload = get_or_none(share,'upload'),
|
||||
overwrite = get_or_none(share,'overwrite'),
|
||||
password = get_or_none('pass_hash', share),
|
||||
public = get_or_none('public', share),
|
||||
upload = upload,
|
||||
overwrite = overwrite,
|
||||
direct = allow_direct,
|
||||
expire = get_or_none(share,'expire'),
|
||||
description = get_or_none(share,'description',"")
|
||||
expire = get_or_none('expire', share),
|
||||
description = get_or_none('description', share, "")
|
||||
)
|
||||
|
||||
@app.route('/logout/<name>', methods=['GET'])
|
||||
def logout(name, password = None):
|
||||
def logout(name):
|
||||
if name in session:
|
||||
del session[name]
|
||||
return render_template(
|
||||
@@ -215,26 +223,24 @@ def logout(name, password = None):
|
||||
name = name
|
||||
)
|
||||
|
||||
@app.route('/direct/<name>/<password>/<filename>', methods=['GET'])
|
||||
def download_direct(name,password,filename):
|
||||
if password != None:
|
||||
session[name] = password
|
||||
@app.route('/direct/<name>/<token>/<filename>', methods=['GET'])
|
||||
def download_direct(name,token,filename):
|
||||
(ok,share) = get_share(name, require_auth = False)
|
||||
if not ok:
|
||||
return share
|
||||
allow_direct = get_or_none(share,'direct_links')
|
||||
allow_direct = get_or_none('direct_links', share)
|
||||
if allow_direct != True:
|
||||
return 'Direct download not allowed', 403
|
||||
token = get_direct_token(share, filename)
|
||||
if token == None:
|
||||
file_token = get_direct_token(share, filename)
|
||||
if file_token == None:
|
||||
return 'Cannot generate token', 400
|
||||
if password != token:
|
||||
if file_token != token:
|
||||
return 'Incorrect token', 403
|
||||
file_path = os.path.join(share['path'], filename)
|
||||
if not os.path.exists(file_path):
|
||||
return 'no such file', 404
|
||||
notify({
|
||||
"recipient": get_or_none(share,'recipient'),
|
||||
"recipient": get_or_none('recipient', share),
|
||||
"share": name,
|
||||
"filename": file_path,
|
||||
"operation": "direct_download"
|
||||
@@ -246,7 +252,7 @@ def download_direct(name,password,filename):
|
||||
@app.route('/download/<name>/<filename>', methods=['GET'])
|
||||
def download_file(name,filename,password = None):
|
||||
if password != None:
|
||||
session[name] = password
|
||||
session[name] = app.config['CRYPTO'].decrypt(password)
|
||||
(ok,share) = get_share(name)
|
||||
if not ok:
|
||||
return share
|
||||
@@ -254,7 +260,7 @@ def download_file(name,filename,password = None):
|
||||
if not os.path.exists(file_path):
|
||||
return 'no such file', 404
|
||||
notify({
|
||||
"recipient": get_or_none(share,'recipient'),
|
||||
"recipient": get_or_none('recipient', share),
|
||||
"share": name,
|
||||
"filename": file_path,
|
||||
"operation": "download"
|
||||
@@ -266,7 +272,7 @@ def download_file(name,filename,password = None):
|
||||
@app.route('/zip/<name>', methods=['GET'])
|
||||
def download_zip(name,password = None):
|
||||
if password != None:
|
||||
session[name] = password
|
||||
session[name] = app.config['CRYPTO'].decrypt(password)
|
||||
(ok,share) = get_share(name)
|
||||
if not ok:
|
||||
return share
|
||||
@@ -276,7 +282,7 @@ def download_zip(name,password = None):
|
||||
zip_clean()
|
||||
zip_path = zip_share(share)
|
||||
notify({
|
||||
"recipient": get_or_none(share,'recipient'),
|
||||
"recipient": get_or_none('recipient', share),
|
||||
"share": name,
|
||||
"filename": name + ".zip",
|
||||
"operation": "zip_download"
|
||||
@@ -289,11 +295,11 @@ def download_zip(name,password = None):
|
||||
|
||||
@app.route('/script/upload/<name>/<password>', methods=['GET'])
|
||||
def script_upload(name = None, password = None):
|
||||
session[name] = password
|
||||
session[name] = app.config['CRYPTO'].decrypt(password)
|
||||
(ok,share) = get_share(name)
|
||||
if not ok:
|
||||
return share
|
||||
if not get_or_none(share,'upload') == True:
|
||||
if not get_or_none('upload', share) == True:
|
||||
return "Upload not allowed",400
|
||||
return """#!/bin/bash
|
||||
test -n "$1" || {
|
||||
@@ -336,7 +342,7 @@ done
|
||||
|
||||
@app.route('/script/download/<name>/<password>', methods=['GET'])
|
||||
def script_download(name = None, password = None):
|
||||
session[name] = password
|
||||
session[name] = app.config['CRYPTO'].decrypt(password)
|
||||
(ok,share) = get_share(name)
|
||||
if not ok:
|
||||
return share
|
||||
@@ -392,7 +398,7 @@ get_file() {
|
||||
|
||||
@app.route('/script/direct/<name>/<password>', methods=['GET'])
|
||||
def script_direct(name = None, password = None):
|
||||
session[name] = password
|
||||
session[name] = app.config['CRYPTO'].decrypt(password)
|
||||
(ok,share) = get_share(name)
|
||||
if not ok:
|
||||
return share
|
||||
@@ -448,11 +454,11 @@ get_file() {
|
||||
|
||||
@app.route('/script/upload_split/<name>/<password>', methods=['GET'])
|
||||
def script_upload_split(name = None, password = None):
|
||||
session[name] = password
|
||||
session[name] = app.config['CRYPTO'].decrypt(password)
|
||||
(ok,share) = get_share(name)
|
||||
if not ok:
|
||||
return share
|
||||
if not get_or_none(share,'upload') == True:
|
||||
if not get_or_none('upload', share) == True:
|
||||
return "Upload not allowed",400
|
||||
return """#!/bin/bash
|
||||
test -n "$1" || {
|
||||
@@ -527,31 +533,6 @@ class uploadJoiner:
|
||||
for part in self.parts:
|
||||
os.remove(part)
|
||||
|
||||
def file_stat(filename):
|
||||
s = os.stat(filename)
|
||||
return {
|
||||
'size': file_size_MB(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_size_MB(num):
|
||||
return "{:,.2f}".format(num/(1024*1024))
|
||||
|
||||
|
||||
def file_date_human(num):
|
||||
return datetime.fromtimestamp(
|
||||
num
|
||||
).strftime(app.config['DATE_FORMAT'])
|
||||
|
||||
def file_versionize(filename):
|
||||
""" Move file to versioned with integer """
|
||||
@@ -574,33 +555,6 @@ def file_versionize(filename):
|
||||
os.rename(filename,new_name)
|
||||
|
||||
|
||||
def get_direct_token(share, filename):
|
||||
if not 'pass_hash' in share:
|
||||
return None
|
||||
return hashlib.sha1(
|
||||
share['pass_hash'].encode('utf-8') + filename.encode('utf-8')
|
||||
).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,none = None):
|
||||
if key in d:
|
||||
return d[key]
|
||||
else:
|
||||
return none
|
||||
|
||||
|
||||
def get_share(name, require_auth = True):
|
||||
share = [x for x in g.shares if x['name'] == name]
|
||||
if len(share) < 1:
|
||||
@@ -632,17 +586,19 @@ def get_share(name, require_auth = True):
|
||||
return (True,share)
|
||||
|
||||
def is_expired(share):
|
||||
expires = get_or_none(share, 'expire')
|
||||
expires = get_or_none('expire', share)
|
||||
if expires:
|
||||
if datetime.now() > datetime.strptime(expires, app.config['DATE_FORMAT']):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def print_debug(s):
|
||||
if app.config['DEBUG']:
|
||||
sys.stderr.write(str(s)+"\n")
|
||||
sys.stderr.flush()
|
||||
|
||||
|
||||
def makedirs_rights(path):
|
||||
# os.makedirs with chown
|
||||
path_list = path.split(os.sep)
|
||||
@@ -667,7 +623,6 @@ def set_rights(path):
|
||||
os.chmod(path, st.st_mode | stat.S_IRGRP | stat.S_IWGRP)
|
||||
|
||||
|
||||
|
||||
def zip_share(share):
|
||||
|
||||
if not os.path.exists(app.config['ZIP_FOLDER']):
|
||||
@@ -695,6 +650,7 @@ def zip_share(share):
|
||||
set_rights(zip_path)
|
||||
return zip_path
|
||||
|
||||
|
||||
def zip_clean():
|
||||
""" delete zip files older than 1 hour """
|
||||
if not os.path.exists(app.config['ZIP_FOLDER']):
|
||||
@@ -708,6 +664,7 @@ def zip_clean():
|
||||
if mtime + 3600 < time.time():
|
||||
os.remove(os.path.join(app.config['ZIP_FOLDER'],file))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user