Compare commits

...

5 Commits

15 changed files with 33 additions and 19 deletions

View File

@@ -28,7 +28,6 @@ jobs:
uses: ./.github/workflows/test-stack-reusable-workflow.yml
with:
python-version: '3.11'
skip-pypuppeteer: true
test-application-3-12:
needs: lint-code

View File

@@ -7,7 +7,7 @@ on:
description: 'Python version to use'
required: true
type: string
default: '3.10'
default: '3.11'
skip-pypuppeteer:
description: 'Skip PyPuppeteer (not supported in 3.11/3.12)'
required: false

View File

@@ -1,8 +1,5 @@
# pip dependencies install stage
# @NOTE! I would love to move to 3.11 but it breaks the async handler in changedetectionio/content_fetchers/puppeteer.py
# If you know how to fix it, please do! and test it for both 3.10 and 3.11
ARG PYTHON_VERSION=3.11
FROM python:${PYTHON_VERSION}-slim-bookworm AS builder

View File

@@ -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)

View File

@@ -217,7 +217,7 @@ nav
<a id="chrome-extension-link"
title="Try our new Chrome Extension!"
href="https://chromewebstore.google.com/detail/changedetectionio-website/kefcfmgmlhmankjmnbijimhofdjekbop">
<img alt="Chrome store icon" src="{{ url_for('static_content', group='images', filename='Google-Chrome-icon.png') }}" alt="Chrome">
<img alt="Chrome store icon" src="{{ url_for('static_content', group='images', filename='google-chrome-icon.png') }}" alt="Chrome">
Chrome Webstore
</a>
</p>

View File

@@ -130,7 +130,7 @@
or ( watch.get_fetch_backend == "system" and system_default_fetcher == 'html_webdriver' )
or "extra_browser_" in watch.get_fetch_backend
%}
<img class="status-icon" src="{{url_for('static_content', group='images', filename='Google-Chrome-icon.png')}}" alt="Using a Chrome browser" title="Using a Chrome browser" >
<img class="status-icon" src="{{url_for('static_content', group='images', filename='google-chrome-icon.png')}}" alt="Using a Chrome browser" title="Using a Chrome browser" >
{% endif %}
{%if watch.is_pdf %}<img class="status-icon" src="{{url_for('static_content', group='images', filename='pdf-icon.svg')}}" title="Converting PDF to text" >{% endif %}
@@ -241,7 +241,7 @@
all {% if active_tag_uuid %} in "{{active_tag.title}}"{%endif%}</a>
</li>
<li>
<a href="{{ url_for('rss.feed', tag=active_tag_uuid, token=app_rss_token)}}"><img alt="RSS Feed" id="feed-icon" src="{{url_for('static_content', group='images', filename='Generic_Feed-icon.svg')}}" height="15"></a>
<a href="{{ url_for('rss.feed', tag=active_tag_uuid, token=app_rss_token)}}"><img alt="RSS Feed" id="feed-icon" src="{{url_for('static_content', group='images', filename='generic_feed-icon.svg')}}" height="15"></a>
</li>
</ul>
{{ pagination.links }}

View File

@@ -75,13 +75,19 @@ function isItemInStock() {
'rupture',
'sold out',
'sold-out',
'stok habis',
'stok kosong',
'stok varian ini habis',
'stokta yok',
'temporarily out of stock',
'temporarily unavailable',
'there were no search results for',
'this item is currently unavailable',
'tickets unavailable',
'tidak dijual',
'tidak tersedia',
'tijdelijk uitverkocht',
'tiket tidak tersedia',
'tükendi',
'unavailable nearby',
'unavailable tickets',

View File

@@ -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)

View File

Before

Width:  |  Height:  |  Size: 569 B

After

Width:  |  Height:  |  Size: 569 B

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -159,7 +159,7 @@
<a id="chrome-extension-link"
title="Chrome Extension - Web Page Change Detection with changedetection.io!"
href="https://chromewebstore.google.com/detail/changedetectionio-website/kefcfmgmlhmankjmnbijimhofdjekbop">
<img alt="Chrome store icon" src="{{url_for('static_content', group='images', filename='Google-Chrome-icon.png')}}">
<img alt="Chrome store icon" src="{{url_for('static_content', group='images', filename='google-chrome-icon.png')}}">
Chrome Webstore
</a>
</p>

View File

@@ -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

View File

@@ -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

View File

@@ -39,7 +39,7 @@ apprise==1.9.2
paho-mqtt!=2.0.*
# Requires extra wheel for rPi
cryptography~=42.0.8
cryptography~=43.0.1
# Used for CSS filtering
beautifulsoup4