Regession - Shared history/diff page with anonymous access turned on should allow screenshot access (#3076)

pull/3077/head
dgtlmoon 2025-04-01 11:30:10 +02:00 zatwierdzone przez GitHub
rodzic 8f9c46bd3f
commit cb62404b8c
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
4 zmienionych plików z 21 dodań i 9 usunięć

Wyświetl plik

@ -20,10 +20,7 @@ def login_optionally_required(func):
has_password_enabled = datastore.data['settings']['application'].get('password') or os.getenv("SALTED_PASS", False)
# Permitted
if request.endpoint and 'static_content' in request.endpoint and request.view_args and request.view_args.get('group') == 'styles':
return func(*args, **kwargs)
# Permitted
elif request.endpoint and 'diff_history_page' in request.endpoint and datastore.data['settings']['application'].get('shared_diff_access'):
if request.endpoint and 'diff_history_page' in request.endpoint and datastore.data['settings']['application'].get('shared_diff_access'):
return func(*args, **kwargs)
elif request.method in flask_login.config.EXEMPT_METHODS:
return func(*args, **kwargs)

Wyświetl plik

@ -233,7 +233,8 @@ def changedetection_app(config=None, datastore_o=None):
if has_password_enabled and not flask_login.current_user.is_authenticated:
# Permitted
if request.endpoint and request.endpoint == 'static_content' and request.view_args and request.view_args.get('group') in ['styles', 'js', 'images', 'favicons']:
if request.endpoint and request.endpoint == 'static_content' and request.view_args:
# Handled by static_content handler
return None
# Permitted
elif request.endpoint and 'login' in request.endpoint:
@ -351,11 +352,15 @@ def changedetection_app(config=None, datastore_o=None):
@app.route("/static/<string:group>/<string:filename>", methods=['GET'])
def static_content(group, filename):
from flask import make_response
import re
group = re.sub(r'[^\w.-]+', '', group.lower())
filename = re.sub(r'[^\w.-]+', '', filename.lower())
if group == 'screenshot':
# Could be sensitive, follow password requirements
if datastore.data['settings']['application']['password'] and not flask_login.current_user.is_authenticated:
abort(403)
if not datastore.data['settings']['application'].get('shared_diff_access'):
abort(403)
screenshot_filename = "last-screenshot.png" if not request.args.get('error_screenshot') else "last-error-screenshot.png"
@ -404,7 +409,7 @@ def changedetection_app(config=None, datastore_o=None):
# These files should be in our subdirectory
try:
return send_from_directory("static/{}".format(group), path=filename)
return send_from_directory(f"static/{group}", path=filename)
except FileNotFoundError:
abort(404)

Wyświetl plik

@ -60,6 +60,11 @@ def test_check_access_control(app, client, live_server):
res = c.get(url_for('static_content', group='styles', filename='404-testetest.css'))
assert res.status_code == 404
# Access to screenshots should be limited by 'shared_diff_access'
path = url_for('static_content', group='screenshot', filename='random-uuid-that-will-404.png', _external=True)
res = c.get(path)
assert res.status_code == 404
# Check wrong password does not let us in
res = c.post(
url_for("login"),
@ -163,7 +168,7 @@ def test_check_access_control(app, client, live_server):
url_for("settings.settings_page"),
data={"application-password": "foobar",
# Should be disabled
# "application-shared_diff_access": "True",
"application-shared_diff_access": "",
"requests-time_between_check-minutes": 180,
'application-fetch_backend': "html_requests"},
follow_redirects=True
@ -176,6 +181,10 @@ def test_check_access_control(app, client, live_server):
# Should be logged out
assert b"Login" in res.data
# Access to screenshots should be limited by 'shared_diff_access'
res = c.get(url_for('static_content', group='screenshot', filename='random-uuid-that-will-403.png'))
assert res.status_code == 403
# The diff page should return something valid when logged out
res = c.get(url_for("ui.ui_views.diff_history_page", uuid="first"))
assert b'Random content' not in res.data

Wyświetl plik

@ -1,6 +1,6 @@
#!/usr/bin/env python3
import json
import urllib
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks
@ -113,6 +113,7 @@ def test_conditions_with_text_and_number(client, live_server):
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
time.sleep(2)
# 75 is > 20 and < 100 and contains "5"
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data