direct links
This commit is contained in:
@@ -29,5 +29,7 @@ location /flees/ {
|
|||||||
- http://host/download/[share name]/[hashed password]/[filename]
|
- http://host/download/[share name]/[hashed password]/[filename]
|
||||||
- upload with curl (etc.)
|
- upload with curl (etc.)
|
||||||
- curl -F file=@my.file http://host/upload/[share name]/[hashed password]
|
- curl -F file=@my.file http://host/upload/[share name]/[hashed password]
|
||||||
|
- "direct link" is a sharing link that does not require other passwords, and is unique to each file.
|
||||||
|
(there should be no danger in sharing a file, and the password to rest of the files leaking)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
60
code/app.py
60
code/app.py
@@ -93,7 +93,13 @@ 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'])):
|
||||||
files.append(file_stat(os.path.join(share['path'],file)))
|
status = file_stat(os.path.join(share['path'],file))
|
||||||
|
status.update({
|
||||||
|
'token': get_direct_token(share, file)
|
||||||
|
})
|
||||||
|
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
|
||||||
return render_template(
|
return render_template(
|
||||||
"list.html",
|
"list.html",
|
||||||
name = share['name'],
|
name = share['name'],
|
||||||
@@ -102,7 +108,7 @@ def list_view(name, password = None):
|
|||||||
public = get_or_none(share,'public'),
|
public = get_or_none(share,'public'),
|
||||||
upload = get_or_none(share,'upload'),
|
upload = get_or_none(share,'upload'),
|
||||||
overwrite = get_or_none(share,'overwrite'),
|
overwrite = get_or_none(share,'overwrite'),
|
||||||
direct = get_or_none(share,'direct_links'),
|
direct = allow_direct,
|
||||||
expire = get_or_none(share,'expire')
|
expire = get_or_none(share,'expire')
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -115,12 +121,27 @@ def logout(name, password = None):
|
|||||||
name = name
|
name = name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.route('/direct/<name>/<password>/<filename>', methods=['GET'])
|
||||||
|
def download_direct(name,password,filename):
|
||||||
|
if password != None:
|
||||||
|
session[name] = password
|
||||||
|
(ok,share) = get_share(name, require_auth = False)
|
||||||
|
if not ok:
|
||||||
|
return share
|
||||||
|
token = get_direct_token(share, filename)
|
||||||
|
if token == None:
|
||||||
|
return 'Cannot generate token', 400
|
||||||
|
if password != 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
|
||||||
|
return send_from_directory(directory=share['path'], filename=filename)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/download/<name>/<password>/<filename>', methods=['GET'])
|
@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,password = None):
|
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
|
||||||
@@ -151,6 +172,12 @@ def file_date_human(num):
|
|||||||
).strftime(app.config['DATE_FORMAT'])
|
).strftime(app.config['DATE_FORMAT'])
|
||||||
|
|
||||||
|
|
||||||
|
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_or_none(d,key):
|
def get_or_none(d,key):
|
||||||
@@ -159,7 +186,8 @@ def get_or_none(d,key):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_share(name):
|
|
||||||
|
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,'No such share')
|
||||||
@@ -167,16 +195,18 @@ def get_share(name):
|
|||||||
if is_expired(share):
|
if is_expired(share):
|
||||||
return (False, 'Share has expired')
|
return (False, 'Share has expired')
|
||||||
authenticated = True
|
authenticated = True
|
||||||
if 'pass_hash' in share:
|
if require_auth:
|
||||||
authenticated = False
|
if 'pass_plain' in share:
|
||||||
if name in session:
|
authenticated = False
|
||||||
if session[name] == share['pass_hash']:
|
if name in session:
|
||||||
authenticated = True
|
if session[name] == hashlib.sha1(share['pass_plain'].encode('utf-8')).hexdigest():
|
||||||
if 'pass_plain' in share:
|
authenticated = True
|
||||||
authenticated = False
|
if 'pass_hash' in share:
|
||||||
if name in session:
|
authenticated = False
|
||||||
if session[name] == hashlib.sha1(share['pass_plain'].encode('utf-8')).hexdigest():
|
if name in session:
|
||||||
authenticated = True
|
if session[name] == share['pass_hash']:
|
||||||
|
authenticated = True
|
||||||
|
|
||||||
if not authenticated:
|
if not authenticated:
|
||||||
return (False,redirect(url_for('authenticate',name=name)))
|
return (False,redirect(url_for('authenticate',name=name)))
|
||||||
if not 'path' in share:
|
if not 'path' in share:
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><a href="{{ url_for('download_file', name = name, filename = entry.name) }}">{{ entry.name }}</a>
|
<td><a href="{{ url_for('download_file', name = name, filename = entry.name) }}">{{ entry.name }}</a>
|
||||||
{% if direct %}
|
{% if direct %}
|
||||||
<a href="{{ url_for('download_file', name = name, password = password, filename = entry.name ) }}" title="Direct share link">❖</a>
|
<a href="{{ url_for('download_direct', name = name, password = entry.token, filename = entry.name ) }}" title="Direct share link">❖</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td class=td_right>{{ entry.size|safe }}
|
<td class=td_right>{{ entry.size|safe }}
|
||||||
<td>{{ entry.mtime|safe }}
|
<td>{{ entry.mtime|safe }}
|
||||||
|
|||||||
Reference in New Issue
Block a user