Skip to content

Commit

Permalink
Merge pull request #64 from ctreffe/develop
Browse files Browse the repository at this point in the history
v0.8.8
  • Loading branch information
jobrachem authored Jun 3, 2021
2 parents 952ca05 + 2addbb5 commit 7789f6b
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 27 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Mortimer v0.8.8 (Released 2021-06-03)

### Added v0.8.8

- .zip archives can be used for uploading experiment resources

## Mortimer v0.8.7 (Released 2021-05-14)

### Fixed v0.8.7
Expand Down
2 changes: 1 addition & 1 deletion src/mortimer/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
# 2) we can import it in setup.py for the same reason
# 3) we can import it into your module module

__version__ = "0.8.7"
__version__ = "0.8.8"
6 changes: 6 additions & 0 deletions src/mortimer/errors/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-

from flask import Blueprint, render_template
from flask_wtf.csrf import CSRFError

errors = Blueprint("erros", __name__)

Expand All @@ -25,3 +26,8 @@ def error_404(error):
def error_500(error):
return render_template('errors/500_alfred.html'), 500


# handle CSRF error
@errors.app_errorhandler(CSRFError)
def csrf_error(e):
return e.description, 400
17 changes: 17 additions & 0 deletions src/mortimer/templates/additional/register_email.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Dear Mortimer Admin,

a new user has registered on your platform.

Username: {{ user }}
Email: {{ email }}

Kind regards,
The Mortimer & Alfred Team
--
Alfred Support

Georg-August-Universität Göttingen
Wirtschafts- und Sozialpsychologie

E-Mail: [email protected]
Web: psych.uni-goettingen.de/ecosop
9 changes: 5 additions & 4 deletions src/mortimer/templates/upload_resources.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@

<div class="content-section">
<div class="article-metadata">

You can upload files with a size up to 10 MB. For larger files, please use an external hosting solution.
You can upload individual files or a <code>.zip</code> archive with multiple files.
Zip-archives are extracted automatically. They are not allowed to contain directories or subdirectories.

<br> <br>

<b>Note:</b> The names of uploaded files are subject to a security check. If a filename is insecure, the upload will
change it to a secure form. An allowed filename must for example not contain slashes (<code>/</code>), umlauts
(<code>äöü</code>) or whitespace. Please make sure that all your filenames are secure.

<br> <br>
<b>Example</b><br>
Not allowed: <code>../../../../home/username/.bashrc</code><br>
Expand Down Expand Up @@ -44,5 +45,5 @@
<!-- Dropzone JavaScript -->

{{ dropzone.load_js() }}
{{ dropzone.config(custom_options='autoProcessQueue: false, addRemoveLinks: true, parallelUploads: 20') }}
{{ dropzone.config(custom_options='autoProcessQueue: false, addRemoveLinks: true', redirect_url=url_for('web_experiments.upload_resources', experiment_title=experiment.title, username=experiment.author, relative_path=relative_path)) }}
{% endblock %}
3 changes: 2 additions & 1 deletion src/mortimer/users/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
ResetPasswordForm,
)
from mortimer.models import User, WebExperiment
from mortimer.utils import send_reset_email, create_fernet
from mortimer.utils import send_reset_email, create_fernet, send_register_email
from flask_login import login_user, current_user, logout_user, login_required

# pylint: disable=no-member
Expand Down Expand Up @@ -43,6 +43,7 @@ def register():
# save user
user.save()
flash("Account created for %s." % form.username.data, "success")
send_register_email(user)
return redirect(url_for("users.login"))

password_hint = "This is a password hint"
Expand Down
18 changes: 18 additions & 0 deletions src/mortimer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,24 @@ def send_reset_email(user):
mail.send(msg)


def send_register_email(user):
sender = current_app.config["MAIL_SENDER_ADDRESS"]
recip = current_app.config.get("ADMIN_MAIL", sender)
msg = Message(
"New registration",
sender=sender,
recipients=[recip]
)

msg.body = render_template(
"additional/register_email.html",
user=user.username,
email=user.email
)

mail.send(msg)


def display_directory(directories: list, parent_directory: str, experiment) -> str:
"""
This is a recursive function. The endpoint is reached if it is called on
Expand Down
75 changes: 54 additions & 21 deletions src/mortimer/web_experiments/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import csv
import json
import hashlib
import zipfile

from pathlib import Path
from datetime import datetime
Expand Down Expand Up @@ -316,6 +317,38 @@ def delete_experiment(username, experiment_title):
return redirect(url_for("web_experiments.user_experiments", username=current_user.username))


def validate_zipfile_filenames(z: zipfile.ZipFile) -> bool:
"""
Validates the filenames of files contained in the input zipfile
object.
If a filename is a directory or is otherwise not secure, validation
will fail.
Returns:
bool: True, if validation succeeds. False otherwise.
"""
valid = True
names = z.namelist()
sanitized_names = [secure_filename(fname) for fname in names]
for n1, n2 in zip(names, sanitized_names):
p1 = Path(n1)
if not n1 == n2:
if not p1.suffix:
flash(f"'{n1}' seems to be a directory, which is not allowed.", "danger")
else:
flash(f"Filename '{n1}' is not secure. Please change it.", "danger")
valid = False
break
if not p1.suffix in current_app.config["DROPZONE_ALLOWED_FILE_TYPE"]:
flash(f"Filetype '{p1.suffix}' of {p1} is not allowed. Upload of \
'{z.fp.filename}' was aborted.", "danger")
valid = False
break

return valid


@web_experiments.route(
"/<username>/<path:experiment_title>/upload_resources/<path:relative_path>",
methods=["POST", "GET"],
Expand All @@ -326,7 +359,7 @@ def upload_resources(username, experiment_title, relative_path):
experiment = WebExperiment.objects.get_or_404(title=experiment_title, author=username)
if experiment.author != current_user.username:
abort(403)

path = os.path.join(experiment.path, relative_path)

path_list = []
Expand All @@ -338,31 +371,31 @@ def upload_resources(username, experiment_title, relative_path):
tail, head = os.path.split(tail)

if request.method == "POST":
# Monkeypatch to get flask to flash messages after upload
from flask import get_flashed_messages
get_flashed_messages()

for key, f in request.files.items():

old_filenames = []
new_filenames = []

if key.startswith("file"):
# exemption from sanitization for __init__.py to allow submodules
if f.filename == "__init__.py":
file_fn = f.filename
file_fn = secure_filename(f.filename)

if f.filename != file_fn:
flash(f"Filename <code>{f.filename}</code> is insecure and was not uploaded. Please change it, for \
example to <code>{file_fn}</code>."
"danger",
)
continue

p = Path(f.filename)
if p.suffix == ".zip":
z = zipfile.ZipFile(f)
valid = validate_zipfile_filenames(z)
if valid:
z.extractall(path)
flash(f"Extracted content of '{z.fp.filename}' to directory '{relative_path}/'.", "info")
else:
file_fn = secure_filename(f.filename)
f.save(os.path.join(path, file_fn))

old_filenames.append(f.filename)
new_filenames.append(file_fn)

# TODO: Display old and new filenames
if old_filenames != new_filenames:
for i in range(len(old_filenames)):
flash(
"Filename changed from <code>%s</code> to <code>%s</code>."
% (old_filenames[i], new_filenames[i]),
"danger",
)
f.save(os.path.join(path, file_fn))

return render_template(
"upload_resources.html",
Expand Down

0 comments on commit 7789f6b

Please sign in to comment.