aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubenwardy <rw@rubenwardy.com>2019-11-18 21:42:56 +0000
committerrubenwardy <rw@rubenwardy.com>2019-11-18 21:42:56 +0000
commitff2a74367f3fe980f08c20c691d451d1ae55b95a (patch)
tree73598d0ba42d4a44aef8c4b58763641dabe9d914
parent3f666d2302f5ad78784f2e8a8362134652eed4b9 (diff)
downloadcheatdb-ff2a74367f3fe980f08c20c691d451d1ae55b95a.tar.xz
Fix download forgery
-rw-r--r--app/__init__.py4
-rw-r--r--app/blueprints/packages/releases.py25
-rw-r--r--app/rediscache.py13
-rw-r--r--config.example.cfg5
-rw-r--r--requirements.txt2
5 files changed, 32 insertions, 17 deletions
diff --git a/app/__init__.py b/app/__init__.py
index a0b4ba5..4c1512a 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -25,13 +25,15 @@ from flask_github import GitHub
from flask_wtf.csrf import CsrfProtect
from flask_flatpages import FlatPages
from flask_babel import Babel
-import os
+import os, redis
app = Flask(__name__, static_folder="public/static")
app.config["FLATPAGES_ROOT"] = "flatpages"
app.config["FLATPAGES_EXTENSION"] = ".md"
app.config.from_pyfile(os.environ["FLASK_CONFIG"])
+r = redis.Redis.from_url(app.config["REDIS_URL"])
+
menu.Menu(app=app)
markdown = Markdown(app, extensions=["fenced_code"], safe_mode=True, output_format="html5")
github = GitHub(app)
diff --git a/app/blueprints/packages/releases.py b/app/blueprints/packages/releases.py
index 89a9a00..60a54bd 100644
--- a/app/blueprints/packages/releases.py
+++ b/app/blueprints/packages/releases.py
@@ -20,6 +20,7 @@ from flask_user import *
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.utils import *
@@ -123,20 +124,18 @@ def download_release(package, id):
if release is None or release.package != package:
abort(404)
- if release is None:
- if "application/zip" in request.accept_mimetypes and \
- not "text/html" in request.accept_mimetypes:
- return "", 204
- else:
- flash("No download available.", "error")
- return redirect(package.getDetailsURL())
- else:
- PackageRelease.query.filter_by(id=release.id).update({
- "downloads": PackageRelease.downloads + 1
- })
- db.session.commit()
+ ip = request.headers.get("X-Forwarded-For") or request.remote_addr
+ if ip is not None:
+ key = make_download_key(ip, release.package)
+ if not has_key(key):
+ set_key(key, "true")
+
+ PackageRelease.query.filter_by(id=release.id).update({
+ "downloads": PackageRelease.downloads + 1
+ })
+ db.session.commit()
- return redirect(release.url, code=300)
+ return redirect(release.url, code=300)
@bp.route("/packages/<author>/<name>/releases/<id>/", methods=["GET", "POST"])
@login_required
diff --git a/app/rediscache.py b/app/rediscache.py
new file mode 100644
index 0000000..718a82e
--- /dev/null
+++ b/app/rediscache.py
@@ -0,0 +1,13 @@
+from . import r
+
+# This file acts as a facade between the releases code and redis,
+# and also means that the releases code avoids knowing about `app`
+
+def make_download_key(ip, package):
+ return ("{}/{}/{}").format(ip, package.author.username, package.name)
+
+def set_key(key, v):
+ r.set(key, v)
+
+def has_key(key):
+ return r.exists(key)
diff --git a/config.example.cfg b/config.example.cfg
index 09aac7f..51e3f50 100644
--- a/config.example.cfg
+++ b/config.example.cfg
@@ -10,8 +10,9 @@ SQLALCHEMY_DATABASE_URI = "sqlite:///../db.sqlite"
GITHUB_CLIENT_ID = ""
GITHUB_CLIENT_SECRET = ""
-CELERY_BROKER_URL='redis://localhost:6379'
-CELERY_RESULT_BACKEND='redis://localhost:6379'
+REDIS_URL='redis://redis:6379'
+CELERY_BROKER_URL='redis://redis:6379'
+CELERY_RESULT_BACKEND='redis://redis:6379'
USER_ENABLE_REGISTER = False
USER_ENABLE_CHANGE_USERNAME = False
diff --git a/requirements.txt b/requirements.txt
index 4067ca0..fd73ebc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -16,7 +16,7 @@ celery==4.1.1
kombu==4.2.0
GitPython~=2.1
lxml~=4.2
-pillow~=5.3
+pillow~=6.2
pyScss~=1.3
redis==2.10.6
psycopg2~=2.7