add CLI tools support
This commit is contained in:
@@ -22,3 +22,11 @@ location /flees/ {
|
|||||||
|
|
||||||
- configure local port in `docker-compose.yaml`
|
- configure local port in `docker-compose.yaml`
|
||||||
|
|
||||||
|
- directly login with URLs:
|
||||||
|
- http://host/list/[share name]/[hashed password]
|
||||||
|
- download with curl (etc.)
|
||||||
|
- http://host/download/[share name]/[hashed password]/[filename]
|
||||||
|
- upload with curl (etc.)
|
||||||
|
- curl -F file=@my.file http://host/upload/[share name]/[hashed password]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
37
code/app.py
37
code/app.py
@@ -47,14 +47,18 @@ def authenticate(name):
|
|||||||
return render_template('authenticate.html',name=name)
|
return render_template('authenticate.html',name=name)
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
user_password = request.form['password'].encode('utf-8')
|
user_password = request.form['password'].encode('utf-8')
|
||||||
session[name] = hashlib.sha256(user_password).hexdigest()
|
session[name] = hashlib.sha1(user_password).hexdigest()
|
||||||
return redirect(url_for('list_view',name=name))
|
return redirect(url_for('list_view',name=name))
|
||||||
|
|
||||||
|
@app.route('/upload/<name>/<password>', methods=['POST'])
|
||||||
@app.route('/upload', methods=['POST'])
|
@app.route('/upload', methods=['POST'])
|
||||||
def upload():
|
def upload(name = None, password = None):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
file = request.files['file']
|
file = request.files['file']
|
||||||
name = request.form['name']
|
if name == None:
|
||||||
|
name = request.form['name']
|
||||||
|
if password != None:
|
||||||
|
session[name] = password
|
||||||
(ok,share) = get_share(name)
|
(ok,share) = get_share(name)
|
||||||
if not ok:
|
if not ok:
|
||||||
return share
|
return share
|
||||||
@@ -65,6 +69,8 @@ def upload():
|
|||||||
file.filename
|
file.filename
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if get_or_none(share, 'overwrite') == False:
|
||||||
|
return "Overwrite forbidden", 403
|
||||||
file.save(filename)
|
file.save(filename)
|
||||||
os.chown(filename, app.config['UID'], -1)
|
os.chown(filename, app.config['UID'], -1)
|
||||||
return redirect(url_for('list_view',name=name))
|
return redirect(url_for('list_view',name=name))
|
||||||
@@ -76,8 +82,11 @@ def send(name):
|
|||||||
return share
|
return share
|
||||||
return render_template('send.html',name=name)
|
return render_template('send.html',name=name)
|
||||||
|
|
||||||
|
@app.route('/list/<name>/<password>', methods=['GET'])
|
||||||
@app.route('/list/<name>', methods=['GET'])
|
@app.route('/list/<name>', methods=['GET'])
|
||||||
def list_view(name):
|
def list_view(name, password = None):
|
||||||
|
if password != None:
|
||||||
|
session[name] = password
|
||||||
(ok,share) = get_share(name)
|
(ok,share) = get_share(name)
|
||||||
if not ok:
|
if not ok:
|
||||||
return share
|
return share
|
||||||
@@ -92,16 +101,28 @@ def list_view(name):
|
|||||||
upload = get_or_none(share,'upload'),
|
upload = get_or_none(share,'upload'),
|
||||||
expire = get_or_none(share,'expire')
|
expire = get_or_none(share,'expire')
|
||||||
)
|
)
|
||||||
#~ return jsonify({"share":share, "files": files})
|
|
||||||
|
|
||||||
|
@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'])
|
@app.route('/download/<name>/<filename>', methods=['GET'])
|
||||||
def download_file(name,filename):
|
def download_file(name,filename,password = None):
|
||||||
|
if password != None:
|
||||||
|
session[name] = password
|
||||||
(ok,share) = get_share(name)
|
(ok,share) = get_share(name)
|
||||||
if not ok:
|
if not ok:
|
||||||
return share
|
return share
|
||||||
file_path = os.path.join(share['path'], filename)
|
file_path = os.path.join(share['path'], filename)
|
||||||
if not os.path.exists(file_path):
|
if not os.path.exists(file_path):
|
||||||
return 'no such file'
|
return 'no such file', 404
|
||||||
return send_from_directory(directory=share['path'], filename=filename)
|
return send_from_directory(directory=share['path'], filename=filename)
|
||||||
|
|
||||||
def file_stat(filename):
|
def file_stat(filename):
|
||||||
@@ -150,7 +171,7 @@ def get_share(name):
|
|||||||
if 'pass_plain' in share:
|
if 'pass_plain' in share:
|
||||||
authenticated = False
|
authenticated = False
|
||||||
if name in session:
|
if name in session:
|
||||||
if session[name] == hashlib.sha256(share['pass_plain'].encode('utf-8')).hexdigest():
|
if session[name] == hashlib.sha1(share['pass_plain'].encode('utf-8')).hexdigest():
|
||||||
authenticated = True
|
authenticated = True
|
||||||
if not authenticated:
|
if not authenticated:
|
||||||
return (False,redirect(url_for('authenticate',name=name)))
|
return (False,redirect(url_for('authenticate',name=name)))
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
{% if public %}
|
{% if public %}
|
||||||
Share is <a href="{{ url_for('index') }}">public</a>
|
Share is <a href="{{ url_for('index') }}">public</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
Share is private
|
Share is <a href="{{ url_for('index') }}">unlisted</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div id=list_expire>
|
<div id=list_expire>
|
||||||
@@ -30,6 +30,9 @@
|
|||||||
Share never expires
|
Share never expires
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
<div id=list_logout>
|
||||||
|
<a href="{{ url_for('logout',name=name) }}">Logout</a> from this share
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=clear></div>
|
<div class=clear></div>
|
||||||
<table class="sortable" id="list_table">
|
<table class="sortable" id="list_table">
|
||||||
|
|||||||
4
code/templates/logout.html
Normal file
4
code/templates/logout.html
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block body %}
|
||||||
|
You are logged out from <a href="{{ url_for('list_view',name=name) }}">{{ name|safe }}</a>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
{
|
{
|
||||||
"workers": 8,
|
"workers": 8,
|
||||||
"timeout": 3600,
|
"timeout": 3600,
|
||||||
|
"uid_comment": "Docker runs as root, this changes owner of written files.",
|
||||||
"uid": 1000,
|
"uid": 1000,
|
||||||
|
"__comment": "most likely you will not change anything after this line",
|
||||||
"data_folder": "data",
|
"data_folder": "data",
|
||||||
"shares_file": "data/shares.json",
|
"shares_file": "data/shares.json",
|
||||||
"date_format": "%Y-%m-%d %H:%M"
|
"date_format": "%Y-%m-%d %H:%M"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"pass_hash": "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
|
"pass_hash": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
|
||||||
"pass_plain": "password",
|
"pass_plain": "password",
|
||||||
"path": "files",
|
"path": "files",
|
||||||
"public": false,
|
"public": false,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ if opts.plain:
|
|||||||
})
|
})
|
||||||
if opts.hashed:
|
if opts.hashed:
|
||||||
share.update({
|
share.update({
|
||||||
'pass_hash': hashlib.sha256(opts.hashed).hexdigest()
|
'pass_hash': hashlib.sha1(opts.hashed).hexdigest()
|
||||||
})
|
})
|
||||||
if opts.expire:
|
if opts.expire:
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user