diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py index f18c43d2b..8d16c24f3 100644 --- a/changedetectionio/__init__.py +++ b/changedetectionio/__init__.py @@ -175,9 +175,8 @@ class User(flask_login.UserMixin): def login_optionally_required(func): @wraps(func) def decorated_view(*args, **kwargs): + has_password_enabled = datastore.data['settings']['application'].get('password') or os.getenv("SALTED_PASS", False) - if not has_password_enabled: - return func(*args, **kwargs) # Permitted if request.endpoint == 'static_content' and request.view_args['group'] == 'styles': @@ -189,16 +188,18 @@ def login_optionally_required(func): elif request.endpoint == 'rss': app_rss_token = datastore.data['settings']['application'].get('rss_access_token') rss_url_token = request.args.get('token') - # Both not none and they are the same - if app_rss_token and rss_url_token and rss_url_token == app_rss_token: - return func(*args, **kwargs) + if rss_url_token != app_rss_token: + return "Access denied, bad token", 403 elif request.method in flask_login.config.EXEMPT_METHODS: return func(*args, **kwargs) elif app.config.get('LOGIN_DISABLED'): return func(*args, **kwargs) + elif not has_password_enabled: + return func(*args, **kwargs) elif not current_user.is_authenticated: return app.login_manager.unauthorized() + return func(*args, **kwargs) return decorated_view diff --git a/changedetectionio/tests/test_rss.py b/changedetectionio/tests/test_rss.py new file mode 100644 index 000000000..30db6a209 --- /dev/null +++ b/changedetectionio/tests/test_rss.py @@ -0,0 +1,39 @@ +#!/usr/bin/python3 + +import time +from flask import url_for +from .util import set_original_response, set_modified_response, live_server_setup, wait_for_all_checks, extract_rss_token_from_UI + + +def test_rss_and_token(client, live_server): + set_original_response() + live_server_setup(live_server) + + # Add our URL to the import page + res = client.post( + url_for("import_page"), + data={"urls": url_for('test_random_content_endpoint', _external=True)}, + follow_redirects=True + ) + + assert b"1 Imported" in res.data + rss_token = extract_rss_token_from_UI(client) + + time.sleep(2) + client.get(url_for("form_watch_checknow"), follow_redirects=True) + time.sleep(2) + + # Add our URL to the import page + res = client.get( + url_for("rss", token="bad token", _external=True), + follow_redirects=True + ) + + assert b"Access denied, bad token" in res.data + + res = client.get( + url_for("rss", token=rss_token, _external=True), + follow_redirects=True + ) + assert b"Access denied, bad token" not in res.data + assert b"Random content" in res.data diff --git a/changedetectionio/tests/util.py b/changedetectionio/tests/util.py index 63f707a08..7a390ad9a 100644 --- a/changedetectionio/tests/util.py +++ b/changedetectionio/tests/util.py @@ -70,6 +70,15 @@ def extract_api_key_from_UI(client): api_key = m.group(1) return api_key.strip() +# kinda funky, but works for now +def extract_rss_token_from_UI(client): + import re + res = client.get( + url_for("index"), + ) + m = re.search('token=(.+?)"', str(res.data)) + token_key = m.group(1) + return token_key.strip() # kinda funky, but works for now def extract_UUID_from_client(client):