Skip to content

Commit

Permalink
Downgrade Werkzeug from 2.1.2 to 2.0.3 to avoid removal errors (CTFd#…
Browse files Browse the repository at this point in the history
…2384)

* Downgrade Werkzeug from 2.1.2 to 2.0.3 to avoid removal errors
* Fix warnings from Werkzeug migration from v1 to v2
  • Loading branch information
ColdHeat authored Aug 5, 2023
1 parent 6c1b970 commit edbbc5f
Show file tree
Hide file tree
Showing 16 changed files with 50 additions and 37 deletions.
2 changes: 1 addition & 1 deletion CTFd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

import jinja2
from flask import Flask, Request
from flask.helpers import safe_join
from flask_babel import Babel
from flask_migrate import upgrade
from jinja2 import FileSystemLoader
from jinja2.sandbox import SandboxedEnvironment
from werkzeug.middleware.proxy_fix import ProxyFix
from werkzeug.utils import safe_join

import CTFd.utils.config
from CTFd import utils
Expand Down
4 changes: 2 additions & 2 deletions CTFd/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ def export_csv():
return send_file(
output,
as_attachment=True,
cache_timeout=-1,
attachment_filename="{name}-{table}.csv".format(
max_age=-1,
download_name="{name}-{table}.csv".format(
name=ctf_config.ctf_name(), table=table
),
)
Expand Down
3 changes: 1 addition & 2 deletions CTFd/utils/uploads/uploaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
import boto3
from botocore.client import Config
from flask import current_app, redirect, send_file
from flask.helpers import safe_join
from freezegun import freeze_time
from werkzeug.utils import secure_filename
from werkzeug.utils import safe_join, secure_filename

from CTFd.utils import get_app_config
from CTFd.utils.encoding import hexencode
Expand Down
8 changes: 7 additions & 1 deletion CTFd/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
session,
url_for,
)
from flask.helpers import safe_join
from jinja2.exceptions import TemplateNotFound
from sqlalchemy.exc import IntegrityError
from werkzeug.utils import safe_join

from CTFd.cache import cache
from CTFd.constants.config import (
Expand Down Expand Up @@ -492,6 +492,9 @@ def themes(theme, path):
# admin pages, so we check that first
for cand_theme in (theme, *config.ctf_theme_candidates())
):
# Handle werkzeug behavior of returning None on malicious paths
if cand_path is None:
abort(404)
if os.path.isfile(cand_path):
return send_file(cand_path)
abort(404)
Expand All @@ -512,6 +515,9 @@ def themes_beta(theme, path):
# admin pages, so we check that first
for cand_theme in (theme, *config.ctf_theme_candidates())
):
# Handle werkzeug behavior of returning None on malicious paths
if cand_path is None:
abort(404)
if os.path.isfile(cand_path):
return send_file(cand_path)
abort(404)
Expand Down
2 changes: 1 addition & 1 deletion requirements.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Flask==2.0.3
Werkzeug==2.1.2
Werkzeug==2.0.3
Flask-SQLAlchemy==2.5.1
Flask-Caching==2.0.2
Flask-Migrate==2.5.3
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ urllib3==1.25.11
# via
# botocore
# requests
werkzeug==2.1.2
werkzeug==2.0.3
# via
# -r requirements.in
# flask
Expand Down
4 changes: 2 additions & 2 deletions tests/admin/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def test_admin_access():
for route in routes:
r = client.get(route)
assert r.status_code == 302
assert r.location.startswith("/login")
assert r.location.startswith("http://localhost/login")

admin = login_as_user(app, name="admin")
routes.remove("/admin")
Expand All @@ -78,5 +78,5 @@ def test_get_admin_as_user():
client = login_as_user(app)
r = client.get("/admin")
assert r.status_code == 302
assert r.location.startswith("/login")
assert r.location.startswith("http://localhost/login")
destroy_ctfd(app)
2 changes: 1 addition & 1 deletion tests/api/v1/user/test_admin_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ def test_api_hint_404():
for endpoint in endpoints:
r = client.get(endpoint.format(1))
assert r.status_code == 302
assert r.location.startswith("/login")
assert r.location.startswith("http://localhost/login")
destroy_ctfd(app)
2 changes: 1 addition & 1 deletion tests/oauth/test_redirect.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_oauth_not_configured():
with app.app_context():
with app.test_client() as client:
r = client.get("/oauth", follow_redirects=False)
assert r.location == "/login"
assert r.location == "http://localhost/login"
r = client.get(r.location)
resp = r.get_data(as_text=True)
assert "OAuth Settings not configured" in resp
Expand Down
4 changes: 2 additions & 2 deletions tests/teams/test_challenges.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_anonymous_users_view_public_challenges_without_team():
with app.test_client() as client:
r = client.get("/challenges")
assert r.status_code == 302
assert r.location.startswith("/login")
assert r.location.startswith("http://localhost/login")

set_config("challenge_visibility", "public")
with app.test_client() as client:
Expand All @@ -61,5 +61,5 @@ def test_anonymous_users_view_public_challenges_without_team():
with login_as_user(app) as client:
r = client.get("/challenges")
assert r.status_code == 302
assert r.location.startswith("/team")
assert r.location.startswith("http://localhost/team")
destroy_ctfd(app)
6 changes: 3 additions & 3 deletions tests/test_themes.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def test_that_ctfd_can_be_deployed_in_subdir():
with app.test_client() as client:
r = client.get("/")
assert r.status_code == 302
assert r.location == "/ctf/setup"
assert r.location == "http://localhost/ctf/setup"

r = client.get("/setup")
with client.session_transaction() as sess:
Expand All @@ -105,13 +105,13 @@ def test_that_ctfd_can_be_deployed_in_subdir():
}
r = client.post("/setup", data=data)
assert r.status_code == 302
assert r.location == "/ctf/"
assert r.location == "http://localhost/ctf/"

c = Client(app)
response = c.get("/")
headers = dict(response.headers)
assert response.status == "302 FOUND"
assert headers["Location"] == "/ctf/?"
assert headers["Location"] == "http://localhost/ctf/"

r = client.get("/challenges")
assert r.status_code == 200
Expand Down
2 changes: 1 addition & 1 deletion tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def test_page_requiring_auth():
with app.test_client() as client:
r = client.get("/this-is-a-route")
assert r.status_code == 302
assert r.location == "/login?next=%2Fthis-is-a-route%3F"
assert r.location == "http://localhost/login?next=%2Fthis-is-a-route%3F"

register_user(app)
client = login_as_user(app)
Expand Down
36 changes: 22 additions & 14 deletions tests/users/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ def test_user_bad_login():
with client.session_transaction() as sess:
assert sess.get("id") is None
r = client.get("/profile")
assert r.location.startswith("/login") # We got redirected to login
assert r.location.startswith(
"http://localhost/login"
) # We got redirected to login
destroy_ctfd(app)


Expand All @@ -130,7 +132,9 @@ def test_user_login():
register_user(app)
client = login_as_user(app)
r = client.get("/profile")
assert r.location is None # We didn't get redirected to login
assert (
r.location != "http://localhost/login"
) # We didn't get redirected to login
assert r.status_code == 200
destroy_ctfd(app)

Expand All @@ -142,7 +146,9 @@ def test_user_login_with_email():
register_user(app)
client = login_as_user(app, name="[email protected]", password="password")
r = client.get("/profile")
assert r.location is None # We didn't get redirected to login
assert (
r.location != "http://localhost/login"
) # We didn't get redirected to login
assert r.status_code == 200
destroy_ctfd(app)

Expand All @@ -155,7 +161,7 @@ def test_user_get_logout():
client = login_as_user(app)
client.get("/logout", follow_redirects=True)
r = client.get("/challenges")
assert r.location == "/login?next=%2Fchallenges%3F"
assert r.location == "http://localhost/login?next=%2Fchallenges%3F"
assert r.status_code == 302
destroy_ctfd(app)

Expand All @@ -176,7 +182,7 @@ def test_user_isnt_admin():
"config",
]:
r = client.get("/admin/{}".format(page))
assert r.location.startswith("/login?next=")
assert r.location.startswith("http://localhost/login?next=")
assert r.status_code == 302
destroy_ctfd(app)

Expand Down Expand Up @@ -296,29 +302,31 @@ def test_user_can_confirm_email(mock_smtp):

client = login_as_user(app, name="user1", password="password")

r = client.get("/confirm")
r = client.get("http://localhost/confirm")
assert "We've sent a confirmation email" in r.get_data(as_text=True)

# smtp send message function was called
mock_smtp.return_value.send_message.assert_called()

with client.session_transaction() as sess:
data = {"nonce": sess.get("nonce")}
r = client.post("/confirm", data=data)
r = client.post("http://localhost/confirm", data=data)
assert "Confirmation email sent to" in r.get_data(as_text=True)

r = client.get("/challenges")
assert r.location == "/confirm" # We got redirected to /confirm
assert (
r.location == "http://localhost/confirm"
) # We got redirected to /confirm

r = client.get("/confirm/" + serialize("[email protected]"))
assert r.location == "/challenges"
r = client.get("http://localhost/confirm/" + serialize("[email protected]"))
assert r.location == "http://localhost/challenges"

# The team is now verified
user = Users.query.filter_by(email="[email protected]").first()
assert user.verified is True

r = client.get("/confirm")
assert r.location == "/settings"
r = client.get("http://localhost/confirm")
assert r.location == "http://localhost/settings"
destroy_ctfd(app)


Expand Down Expand Up @@ -454,7 +462,7 @@ def test_registration_code_required():
data["registration_code"] = "secret-sauce"
r = client.post("/register", data=data)
assert r.status_code == 302
assert r.location.startswith("/challenges")
assert r.location.startswith("http://localhost/challenges")
destroy_ctfd(app)


Expand Down Expand Up @@ -484,5 +492,5 @@ def test_registration_code_allows_numeric():
data["registration_code"] = "1234567890"
r = client.post("/register", data=data)
assert r.status_code == 302
assert r.location.startswith("/challenges")
assert r.location.startswith("http://localhost/challenges")
destroy_ctfd(app)
4 changes: 2 additions & 2 deletions tests/users/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ def test_user_needs_all_required_fields():

r = client.get("/challenges")
assert r.status_code == 302
assert r.location.startswith("/settings")
assert r.location.startswith("http://localhost/settings")

# Populate the non-required fields
r = client.patch(
Expand All @@ -277,7 +277,7 @@ def test_user_needs_all_required_fields():
# I should still be restricted from seeing challenges
r = client.get("/challenges")
assert r.status_code == 302
assert r.location.startswith("/settings")
assert r.location.startswith("http://localhost/settings")

# I should still see all fields b/c I don't have a complete profile
r = client.get("/settings")
Expand Down
4 changes: 2 additions & 2 deletions tests/users/test_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def test_ctfd_setup_redirect():
with app.test_client() as client:
r = client.get("/users")
assert r.status_code == 302
assert r.location == "/setup"
assert r.location == "http://localhost/setup"

# Files in /themes load properly
r = client.get("/themes/core/static/css/main.dev.css")
Expand Down Expand Up @@ -52,5 +52,5 @@ def test_ctfd_setup_verification():
data["email"] = "[email protected]"
r = client.post("/setup", data=data)
assert r.status_code == 302
assert r.location == "/"
assert r.location == "http://localhost/"
destroy_ctfd(app)
2 changes: 1 addition & 1 deletion tests/utils/test_sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def test_session_invalidation_on_admin_password_change():
r = user.get("/settings")
# User's password was changed
# They should be logged out
assert r.location.startswith("/login")
assert r.location.startswith("http://localhost/login")
assert r.status_code == 302
destroy_ctfd(app)

Expand Down

0 comments on commit edbbc5f

Please sign in to comment.