Add validation to zip releases

This commit is contained in:
rubenwardy 2020-01-19 01:37:15 +00:00
parent ec8a88a7a8
commit facdd35b11
4 changed files with 52 additions and 15 deletions

@ -22,7 +22,7 @@ from . import bp
from app.rediscache import has_key, set_key, make_download_key
from app.models import *
from app.tasks.importtasks import makeVCSRelease
from app.tasks.importtasks import makeVCSRelease, checkZIPRelease
from app.utils import *
from celery import uuid
@ -98,22 +98,25 @@ def create_release(package):
return redirect(url_for("tasks.check", id=rel.task_id, r=rel.getEditURL()))
else:
uploadedPath = doFileUpload(form.fileUpload.data, "zip", "a zip file")
if uploadedPath is not None:
uploadedUrl, uploadedPath = doFileUpload(form.fileUpload.data, "zip", "a zip file")
if uploadedUrl is not None:
rel = PackageRelease()
rel.package = package
rel.title = form["title"].data
rel.url = uploadedPath
rel.url = uploadedUrl
rel.task_id = uuid()
rel.min_rel = form["min_rel"].data.getActual()
rel.max_rel = form["max_rel"].data.getActual()
rel.approve(current_user)
db.session.add(rel)
db.session.commit()
checkZIPRelease.apply_async((rel.id, uploadedPath), task_id=rel.task_id)
msg = "{}: Release {} created".format(package.title, rel.title)
triggerNotif(package.author, current_user, msg, rel.getEditURL())
db.session.commit()
return redirect(package.getDetailsURL())
return redirect(url_for("tasks.check", id=rel.task_id, r=rel.getEditURL()))
return render_template("packages/release_new.html", package=package, form=form)

@ -50,13 +50,13 @@ def create_screenshot(package, id=None):
# Initial form class from post data and default data
form = CreateScreenshotForm()
if request.method == "POST" and form.validate():
uploadedPath = doFileUpload(form.fileUpload.data, "image",
uploadedUrl, uploadedPath = doFileUpload(form.fileUpload.data, "image",
"a PNG or JPG image file")
if uploadedPath is not None:
if uploadedUrl is not None:
ss = PackageScreenshot()
ss.package = package
ss.title = form["title"].data or "Untitled"
ss.url = uploadedPath
ss.url = uploadedUrl
ss.approved = package.checkPerm(current_user, Permission.APPROVE_SCREENSHOT)
db.session.add(ss)

@ -22,6 +22,8 @@ from flask_sqlalchemy import SQLAlchemy
from urllib.error import HTTPError
import urllib.request
from urllib.parse import urlparse, quote_plus, urlsplit
from zipfile import ZipFile
from app import app
from app.models import *
from app.tasks import celery, TaskError
@ -133,12 +135,17 @@ def generateGitURL(urlstr):
return "http://:@" + netloc + path + query
def getTempDir():
return os.path.join(tempfile.gettempdir(), randomString(10))
# Clones a repo from an unvalidated URL.
# Returns a tuple of path and repo on sucess.
# Throws `TaskError` on failure.
# Caller is responsible for deleting returned directory.
def cloneRepo(urlstr, ref=None, recursive=False):
gitDir = tempfile.gettempdir() + "/" + randomString(10)
gitDir = getTempDir()
err = None
try:
@ -222,6 +229,32 @@ def makeVCSReleaseFromGithub(id, branch, release, url):
return release.url
@celery.task()
def checkZIPRelease(id, path):
release = PackageRelease.query.get(id)
if release is None:
raise TaskError("No such release!")
elif release.package is None:
raise TaskError("No package attached to release")
temp = getTempDir()
try:
with ZipFile(path, 'r') as zip_ref:
zip_ref.extractall(temp)
try:
tree = build_tree(temp, expected_type=ContentType[release.package.type.name], \
author=release.package.author.username, name=release.package.name)
except MinetestCheckError as err:
raise TaskError(str(err))
release.task_id = None
release.approve(release.package.author)
db.session.commit()
finally:
shutil.rmtree(temp)
@celery.task()
def makeVCSRelease(id, branch):

@ -49,7 +49,7 @@ def randomString(n):
def doFileUpload(file, fileType, fileTypeDesc):
if not file or file is None or file.filename == "":
flash("No selected file", "error")
return None
return None, None
assert os.path.isdir(app.config["UPLOAD_DIR"]), "UPLOAD_DIR must exist"
@ -66,17 +66,18 @@ def doFileUpload(file, fileType, fileTypeDesc):
ext = getExtension(file.filename)
if ext is None or not ext in allowedExtensions:
flash("Please upload load " + fileTypeDesc, "danger")
return None
return None, None
if isImage and not isAllowedImage(file.stream.read()):
flash("Uploaded image isn't actually an image", "danger")
return None
return None, None
file.stream.seek(0)
filename = randomString(10) + "." + ext
file.save(os.path.join(app.config["UPLOAD_DIR"], filename))
return "/uploads/" + filename
filepath = os.path.join(app.config["UPLOAD_DIR"], filename)
file.save(filepath)
return "/uploads/" + filename, filepath
def make_flask_user_password(plaintext_str):
# http://passlib.readthedocs.io/en/stable/modular_crypt_format.html